xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * AMD 10Gb Ethernet driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This file is available to you under your choice of the following two
5*4882a593Smuzhiyun  * licenses:
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * License 1: GPLv2
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * This file is free software; you may copy, redistribute and/or modify
12*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
13*4882a593Smuzhiyun  * the Free Software Foundation, either version 2 of the License, or (at
14*4882a593Smuzhiyun  * your option) any later version.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * This file is distributed in the hope that it will be useful, but
17*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
18*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19*4882a593Smuzhiyun  * General Public License for more details.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License
22*4882a593Smuzhiyun  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * This file incorporates work covered by the following copyright and
25*4882a593Smuzhiyun  * permission notice:
26*4882a593Smuzhiyun  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
27*4882a593Smuzhiyun  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
28*4882a593Smuzhiyun  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
29*4882a593Smuzhiyun  *     and you.
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  *     The Software IS NOT an item of Licensed Software or Licensed Product
32*4882a593Smuzhiyun  *     under any End User Software License Agreement or Agreement for Licensed
33*4882a593Smuzhiyun  *     Product with Synopsys or any supplement thereto.  Permission is hereby
34*4882a593Smuzhiyun  *     granted, free of charge, to any person obtaining a copy of this software
35*4882a593Smuzhiyun  *     annotated with this license and the Software, to deal in the Software
36*4882a593Smuzhiyun  *     without restriction, including without limitation the rights to use,
37*4882a593Smuzhiyun  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
38*4882a593Smuzhiyun  *     of the Software, and to permit persons to whom the Software is furnished
39*4882a593Smuzhiyun  *     to do so, subject to the following conditions:
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  *     The above copyright notice and this permission notice shall be included
42*4882a593Smuzhiyun  *     in all copies or substantial portions of the Software.
43*4882a593Smuzhiyun  *
44*4882a593Smuzhiyun  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
45*4882a593Smuzhiyun  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46*4882a593Smuzhiyun  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47*4882a593Smuzhiyun  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
48*4882a593Smuzhiyun  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49*4882a593Smuzhiyun  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50*4882a593Smuzhiyun  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51*4882a593Smuzhiyun  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52*4882a593Smuzhiyun  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53*4882a593Smuzhiyun  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54*4882a593Smuzhiyun  *     THE POSSIBILITY OF SUCH DAMAGE.
55*4882a593Smuzhiyun  *
56*4882a593Smuzhiyun  *
57*4882a593Smuzhiyun  * License 2: Modified BSD
58*4882a593Smuzhiyun  *
59*4882a593Smuzhiyun  * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
60*4882a593Smuzhiyun  * All rights reserved.
61*4882a593Smuzhiyun  *
62*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
63*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions are met:
64*4882a593Smuzhiyun  *     * Redistributions of source code must retain the above copyright
65*4882a593Smuzhiyun  *       notice, this list of conditions and the following disclaimer.
66*4882a593Smuzhiyun  *     * Redistributions in binary form must reproduce the above copyright
67*4882a593Smuzhiyun  *       notice, this list of conditions and the following disclaimer in the
68*4882a593Smuzhiyun  *       documentation and/or other materials provided with the distribution.
69*4882a593Smuzhiyun  *     * Neither the name of Advanced Micro Devices, Inc. nor the
70*4882a593Smuzhiyun  *       names of its contributors may be used to endorse or promote products
71*4882a593Smuzhiyun  *       derived from this software without specific prior written permission.
72*4882a593Smuzhiyun  *
73*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
74*4882a593Smuzhiyun  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75*4882a593Smuzhiyun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76*4882a593Smuzhiyun  * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
77*4882a593Smuzhiyun  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78*4882a593Smuzhiyun  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
79*4882a593Smuzhiyun  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
80*4882a593Smuzhiyun  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
81*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
82*4882a593Smuzhiyun  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83*4882a593Smuzhiyun  *
84*4882a593Smuzhiyun  * This file incorporates work covered by the following copyright and
85*4882a593Smuzhiyun  * permission notice:
86*4882a593Smuzhiyun  *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
87*4882a593Smuzhiyun  *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
88*4882a593Smuzhiyun  *     Inc. unless otherwise expressly agreed to in writing between Synopsys
89*4882a593Smuzhiyun  *     and you.
90*4882a593Smuzhiyun  *
91*4882a593Smuzhiyun  *     The Software IS NOT an item of Licensed Software or Licensed Product
92*4882a593Smuzhiyun  *     under any End User Software License Agreement or Agreement for Licensed
93*4882a593Smuzhiyun  *     Product with Synopsys or any supplement thereto.  Permission is hereby
94*4882a593Smuzhiyun  *     granted, free of charge, to any person obtaining a copy of this software
95*4882a593Smuzhiyun  *     annotated with this license and the Software, to deal in the Software
96*4882a593Smuzhiyun  *     without restriction, including without limitation the rights to use,
97*4882a593Smuzhiyun  *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98*4882a593Smuzhiyun  *     of the Software, and to permit persons to whom the Software is furnished
99*4882a593Smuzhiyun  *     to do so, subject to the following conditions:
100*4882a593Smuzhiyun  *
101*4882a593Smuzhiyun  *     The above copyright notice and this permission notice shall be included
102*4882a593Smuzhiyun  *     in all copies or substantial portions of the Software.
103*4882a593Smuzhiyun  *
104*4882a593Smuzhiyun  *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
105*4882a593Smuzhiyun  *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
106*4882a593Smuzhiyun  *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
107*4882a593Smuzhiyun  *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
108*4882a593Smuzhiyun  *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
109*4882a593Smuzhiyun  *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
110*4882a593Smuzhiyun  *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
111*4882a593Smuzhiyun  *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
112*4882a593Smuzhiyun  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
113*4882a593Smuzhiyun  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
114*4882a593Smuzhiyun  *     THE POSSIBILITY OF SUCH DAMAGE.
115*4882a593Smuzhiyun  */
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #include <linux/interrupt.h>
118*4882a593Smuzhiyun #include <linux/module.h>
119*4882a593Smuzhiyun #include <linux/kmod.h>
120*4882a593Smuzhiyun #include <linux/mdio.h>
121*4882a593Smuzhiyun #include <linux/phy.h>
122*4882a593Smuzhiyun #include <linux/of.h>
123*4882a593Smuzhiyun #include <linux/bitops.h>
124*4882a593Smuzhiyun #include <linux/jiffies.h>
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun #include "xgbe.h"
127*4882a593Smuzhiyun #include "xgbe-common.h"
128*4882a593Smuzhiyun 
xgbe_phy_module_eeprom(struct xgbe_prv_data * pdata,struct ethtool_eeprom * eeprom,u8 * data)129*4882a593Smuzhiyun static int xgbe_phy_module_eeprom(struct xgbe_prv_data *pdata,
130*4882a593Smuzhiyun 				  struct ethtool_eeprom *eeprom, u8 *data)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	if (!pdata->phy_if.phy_impl.module_eeprom)
133*4882a593Smuzhiyun 		return -ENXIO;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.module_eeprom(pdata, eeprom, data);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
xgbe_phy_module_info(struct xgbe_prv_data * pdata,struct ethtool_modinfo * modinfo)138*4882a593Smuzhiyun static int xgbe_phy_module_info(struct xgbe_prv_data *pdata,
139*4882a593Smuzhiyun 				struct ethtool_modinfo *modinfo)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	if (!pdata->phy_if.phy_impl.module_info)
142*4882a593Smuzhiyun 		return -ENXIO;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.module_info(pdata, modinfo);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
xgbe_an37_clear_interrupts(struct xgbe_prv_data * pdata)147*4882a593Smuzhiyun static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	int reg;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
152*4882a593Smuzhiyun 	reg &= ~XGBE_AN_CL37_INT_MASK;
153*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
xgbe_an37_disable_interrupts(struct xgbe_prv_data * pdata)156*4882a593Smuzhiyun static void xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	int reg;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
161*4882a593Smuzhiyun 	reg &= ~XGBE_AN_CL37_INT_MASK;
162*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
165*4882a593Smuzhiyun 	reg &= ~XGBE_PCS_CL37_BP;
166*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
xgbe_an37_enable_interrupts(struct xgbe_prv_data * pdata)169*4882a593Smuzhiyun static void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	int reg;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
174*4882a593Smuzhiyun 	reg |= XGBE_PCS_CL37_BP;
175*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
178*4882a593Smuzhiyun 	reg |= XGBE_AN_CL37_INT_MASK;
179*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
xgbe_an73_clear_interrupts(struct xgbe_prv_data * pdata)182*4882a593Smuzhiyun static void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
xgbe_an73_disable_interrupts(struct xgbe_prv_data * pdata)187*4882a593Smuzhiyun static void xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
xgbe_an73_enable_interrupts(struct xgbe_prv_data * pdata)192*4882a593Smuzhiyun static void xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
xgbe_an_enable_interrupts(struct xgbe_prv_data * pdata)197*4882a593Smuzhiyun static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	switch (pdata->an_mode) {
200*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
201*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
202*4882a593Smuzhiyun 		xgbe_an73_enable_interrupts(pdata);
203*4882a593Smuzhiyun 		break;
204*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
205*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
206*4882a593Smuzhiyun 		xgbe_an37_enable_interrupts(pdata);
207*4882a593Smuzhiyun 		break;
208*4882a593Smuzhiyun 	default:
209*4882a593Smuzhiyun 		break;
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
xgbe_an_clear_interrupts_all(struct xgbe_prv_data * pdata)213*4882a593Smuzhiyun static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	xgbe_an73_clear_interrupts(pdata);
216*4882a593Smuzhiyun 	xgbe_an37_clear_interrupts(pdata);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
xgbe_kr_mode(struct xgbe_prv_data * pdata)219*4882a593Smuzhiyun static void xgbe_kr_mode(struct xgbe_prv_data *pdata)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	/* Set MAC to 10G speed */
222*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_10000);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
225*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
xgbe_kx_2500_mode(struct xgbe_prv_data * pdata)228*4882a593Smuzhiyun static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	/* Set MAC to 2.5G speed */
231*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_2500);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
234*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
xgbe_kx_1000_mode(struct xgbe_prv_data * pdata)237*4882a593Smuzhiyun static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	/* Set MAC to 1G speed */
240*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_1000);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
243*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
xgbe_sfi_mode(struct xgbe_prv_data * pdata)246*4882a593Smuzhiyun static void xgbe_sfi_mode(struct xgbe_prv_data *pdata)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	/* If a KR re-driver is present, change to KR mode instead */
249*4882a593Smuzhiyun 	if (pdata->kr_redrv)
250*4882a593Smuzhiyun 		return xgbe_kr_mode(pdata);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* Set MAC to 10G speed */
253*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_10000);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
256*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SFI);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
xgbe_x_mode(struct xgbe_prv_data * pdata)259*4882a593Smuzhiyun static void xgbe_x_mode(struct xgbe_prv_data *pdata)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	/* Set MAC to 1G speed */
262*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_1000);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
265*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_X);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
xgbe_sgmii_1000_mode(struct xgbe_prv_data * pdata)268*4882a593Smuzhiyun static void xgbe_sgmii_1000_mode(struct xgbe_prv_data *pdata)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	/* Set MAC to 1G speed */
271*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_1000);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
274*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_1000);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
xgbe_sgmii_100_mode(struct xgbe_prv_data * pdata)277*4882a593Smuzhiyun static void xgbe_sgmii_100_mode(struct xgbe_prv_data *pdata)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	/* Set MAC to 1G speed */
280*4882a593Smuzhiyun 	pdata->hw_if.set_speed(pdata, SPEED_1000);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	/* Call PHY implementation support to complete rate change */
283*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_SGMII_100);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
xgbe_cur_mode(struct xgbe_prv_data * pdata)286*4882a593Smuzhiyun static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.cur_mode(pdata);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
xgbe_in_kr_mode(struct xgbe_prv_data * pdata)291*4882a593Smuzhiyun static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
xgbe_change_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)296*4882a593Smuzhiyun static void xgbe_change_mode(struct xgbe_prv_data *pdata,
297*4882a593Smuzhiyun 			     enum xgbe_mode mode)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	switch (mode) {
300*4882a593Smuzhiyun 	case XGBE_MODE_KX_1000:
301*4882a593Smuzhiyun 		xgbe_kx_1000_mode(pdata);
302*4882a593Smuzhiyun 		break;
303*4882a593Smuzhiyun 	case XGBE_MODE_KX_2500:
304*4882a593Smuzhiyun 		xgbe_kx_2500_mode(pdata);
305*4882a593Smuzhiyun 		break;
306*4882a593Smuzhiyun 	case XGBE_MODE_KR:
307*4882a593Smuzhiyun 		xgbe_kr_mode(pdata);
308*4882a593Smuzhiyun 		break;
309*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_100:
310*4882a593Smuzhiyun 		xgbe_sgmii_100_mode(pdata);
311*4882a593Smuzhiyun 		break;
312*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_1000:
313*4882a593Smuzhiyun 		xgbe_sgmii_1000_mode(pdata);
314*4882a593Smuzhiyun 		break;
315*4882a593Smuzhiyun 	case XGBE_MODE_X:
316*4882a593Smuzhiyun 		xgbe_x_mode(pdata);
317*4882a593Smuzhiyun 		break;
318*4882a593Smuzhiyun 	case XGBE_MODE_SFI:
319*4882a593Smuzhiyun 		xgbe_sfi_mode(pdata);
320*4882a593Smuzhiyun 		break;
321*4882a593Smuzhiyun 	case XGBE_MODE_UNKNOWN:
322*4882a593Smuzhiyun 		break;
323*4882a593Smuzhiyun 	default:
324*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev,
325*4882a593Smuzhiyun 			  "invalid operation mode requested (%u)\n", mode);
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
xgbe_switch_mode(struct xgbe_prv_data * pdata)329*4882a593Smuzhiyun static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
xgbe_set_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)334*4882a593Smuzhiyun static bool xgbe_set_mode(struct xgbe_prv_data *pdata,
335*4882a593Smuzhiyun 			  enum xgbe_mode mode)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	if (mode == xgbe_cur_mode(pdata))
338*4882a593Smuzhiyun 		return false;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	xgbe_change_mode(pdata, mode);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return true;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
xgbe_use_mode(struct xgbe_prv_data * pdata,enum xgbe_mode mode)345*4882a593Smuzhiyun static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
346*4882a593Smuzhiyun 			  enum xgbe_mode mode)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.use_mode(pdata, mode);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
xgbe_an37_set(struct xgbe_prv_data * pdata,bool enable,bool restart)351*4882a593Smuzhiyun static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
352*4882a593Smuzhiyun 			  bool restart)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun 	unsigned int reg;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
357*4882a593Smuzhiyun 	reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (enable)
360*4882a593Smuzhiyun 		reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (restart)
363*4882a593Smuzhiyun 		reg |= MDIO_VEND2_CTRL1_AN_RESTART;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
xgbe_an37_restart(struct xgbe_prv_data * pdata)368*4882a593Smuzhiyun static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	xgbe_an37_enable_interrupts(pdata);
371*4882a593Smuzhiyun 	xgbe_an37_set(pdata, true, true);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL37 AN enabled/restarted\n");
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
xgbe_an37_disable(struct xgbe_prv_data * pdata)376*4882a593Smuzhiyun static void xgbe_an37_disable(struct xgbe_prv_data *pdata)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	xgbe_an37_set(pdata, false, false);
379*4882a593Smuzhiyun 	xgbe_an37_disable_interrupts(pdata);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL37 AN disabled\n");
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
xgbe_an73_set(struct xgbe_prv_data * pdata,bool enable,bool restart)384*4882a593Smuzhiyun static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
385*4882a593Smuzhiyun 			  bool restart)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	unsigned int reg;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/* Disable KR training for now */
390*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
391*4882a593Smuzhiyun 	reg &= ~XGBE_KR_TRAINING_ENABLE;
392*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/* Update AN settings */
395*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
396*4882a593Smuzhiyun 	reg &= ~MDIO_AN_CTRL1_ENABLE;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	if (enable)
399*4882a593Smuzhiyun 		reg |= MDIO_AN_CTRL1_ENABLE;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (restart)
402*4882a593Smuzhiyun 		reg |= MDIO_AN_CTRL1_RESTART;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
xgbe_an73_restart(struct xgbe_prv_data * pdata)407*4882a593Smuzhiyun static void xgbe_an73_restart(struct xgbe_prv_data *pdata)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	xgbe_an73_enable_interrupts(pdata);
410*4882a593Smuzhiyun 	xgbe_an73_set(pdata, true, true);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n");
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
xgbe_an73_disable(struct xgbe_prv_data * pdata)415*4882a593Smuzhiyun static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	xgbe_an73_set(pdata, false, false);
418*4882a593Smuzhiyun 	xgbe_an73_disable_interrupts(pdata);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	pdata->an_start = 0;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
xgbe_an_restart(struct xgbe_prv_data * pdata)425*4882a593Smuzhiyun static void xgbe_an_restart(struct xgbe_prv_data *pdata)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	if (pdata->phy_if.phy_impl.an_pre)
428*4882a593Smuzhiyun 		pdata->phy_if.phy_impl.an_pre(pdata);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	switch (pdata->an_mode) {
431*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
432*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
433*4882a593Smuzhiyun 		xgbe_an73_restart(pdata);
434*4882a593Smuzhiyun 		break;
435*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
436*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
437*4882a593Smuzhiyun 		xgbe_an37_restart(pdata);
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun 	default:
440*4882a593Smuzhiyun 		break;
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
xgbe_an_disable(struct xgbe_prv_data * pdata)444*4882a593Smuzhiyun static void xgbe_an_disable(struct xgbe_prv_data *pdata)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	if (pdata->phy_if.phy_impl.an_post)
447*4882a593Smuzhiyun 		pdata->phy_if.phy_impl.an_post(pdata);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	switch (pdata->an_mode) {
450*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
451*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
452*4882a593Smuzhiyun 		xgbe_an73_disable(pdata);
453*4882a593Smuzhiyun 		break;
454*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
455*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
456*4882a593Smuzhiyun 		xgbe_an37_disable(pdata);
457*4882a593Smuzhiyun 		break;
458*4882a593Smuzhiyun 	default:
459*4882a593Smuzhiyun 		break;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
xgbe_an_disable_all(struct xgbe_prv_data * pdata)463*4882a593Smuzhiyun static void xgbe_an_disable_all(struct xgbe_prv_data *pdata)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	xgbe_an73_disable(pdata);
466*4882a593Smuzhiyun 	xgbe_an37_disable(pdata);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
xgbe_an73_tx_training(struct xgbe_prv_data * pdata,enum xgbe_rx * state)469*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
470*4882a593Smuzhiyun 					  enum xgbe_rx *state)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	unsigned int ad_reg, lp_reg, reg;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	*state = XGBE_RX_COMPLETE;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	/* If we're not in KR mode then we're done */
477*4882a593Smuzhiyun 	if (!xgbe_in_kr_mode(pdata))
478*4882a593Smuzhiyun 		return XGBE_AN_PAGE_RECEIVED;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* Enable/Disable FEC */
481*4882a593Smuzhiyun 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
482*4882a593Smuzhiyun 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
485*4882a593Smuzhiyun 	reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
486*4882a593Smuzhiyun 	if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
487*4882a593Smuzhiyun 		reg |= pdata->fec_ability;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	/* Start KR training */
492*4882a593Smuzhiyun 	if (pdata->phy_if.phy_impl.kr_training_pre)
493*4882a593Smuzhiyun 		pdata->phy_if.phy_impl.kr_training_pre(pdata);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
496*4882a593Smuzhiyun 	reg |= XGBE_KR_TRAINING_ENABLE;
497*4882a593Smuzhiyun 	reg |= XGBE_KR_TRAINING_START;
498*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev,
501*4882a593Smuzhiyun 		  "KR training initiated\n");
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (pdata->phy_if.phy_impl.kr_training_post)
504*4882a593Smuzhiyun 		pdata->phy_if.phy_impl.kr_training_post(pdata);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	return XGBE_AN_PAGE_RECEIVED;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
xgbe_an73_tx_xnp(struct xgbe_prv_data * pdata,enum xgbe_rx * state)509*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata,
510*4882a593Smuzhiyun 				     enum xgbe_rx *state)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	u16 msg;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	*state = XGBE_RX_XNP;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	msg = XGBE_XNP_MCF_NULL_MESSAGE;
517*4882a593Smuzhiyun 	msg |= XGBE_XNP_MP_FORMATTED;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
520*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
521*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	return XGBE_AN_PAGE_RECEIVED;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
xgbe_an73_rx_bpa(struct xgbe_prv_data * pdata,enum xgbe_rx * state)526*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata,
527*4882a593Smuzhiyun 				     enum xgbe_rx *state)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	unsigned int link_support;
530*4882a593Smuzhiyun 	unsigned int reg, ad_reg, lp_reg;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	/* Read Base Ability register 2 first */
533*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	/* Check for a supported mode, otherwise restart in a different one */
536*4882a593Smuzhiyun 	link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
537*4882a593Smuzhiyun 	if (!(reg & link_support))
538*4882a593Smuzhiyun 		return XGBE_AN_INCOMPAT_LINK;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	/* Check Extended Next Page support */
541*4882a593Smuzhiyun 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
542*4882a593Smuzhiyun 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
545*4882a593Smuzhiyun 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
546*4882a593Smuzhiyun 	       ? xgbe_an73_tx_xnp(pdata, state)
547*4882a593Smuzhiyun 	       : xgbe_an73_tx_training(pdata, state);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
xgbe_an73_rx_xnp(struct xgbe_prv_data * pdata,enum xgbe_rx * state)550*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata,
551*4882a593Smuzhiyun 				     enum xgbe_rx *state)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	unsigned int ad_reg, lp_reg;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* Check Extended Next Page support */
556*4882a593Smuzhiyun 	ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
557*4882a593Smuzhiyun 	lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
560*4882a593Smuzhiyun 		(lp_reg & XGBE_XNP_NP_EXCHANGE))
561*4882a593Smuzhiyun 	       ? xgbe_an73_tx_xnp(pdata, state)
562*4882a593Smuzhiyun 	       : xgbe_an73_tx_training(pdata, state);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
xgbe_an73_page_received(struct xgbe_prv_data * pdata)565*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	enum xgbe_rx *state;
568*4882a593Smuzhiyun 	unsigned long an_timeout;
569*4882a593Smuzhiyun 	enum xgbe_an ret;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	if (!pdata->an_start) {
572*4882a593Smuzhiyun 		pdata->an_start = jiffies;
573*4882a593Smuzhiyun 	} else {
574*4882a593Smuzhiyun 		an_timeout = pdata->an_start +
575*4882a593Smuzhiyun 			     msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
576*4882a593Smuzhiyun 		if (time_after(jiffies, an_timeout)) {
577*4882a593Smuzhiyun 			/* Auto-negotiation timed out, reset state */
578*4882a593Smuzhiyun 			pdata->kr_state = XGBE_RX_BPA;
579*4882a593Smuzhiyun 			pdata->kx_state = XGBE_RX_BPA;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 			pdata->an_start = jiffies;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 			netif_dbg(pdata, link, pdata->netdev,
584*4882a593Smuzhiyun 				  "CL73 AN timed out, resetting state\n");
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state
589*4882a593Smuzhiyun 				       : &pdata->kx_state;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	switch (*state) {
592*4882a593Smuzhiyun 	case XGBE_RX_BPA:
593*4882a593Smuzhiyun 		ret = xgbe_an73_rx_bpa(pdata, state);
594*4882a593Smuzhiyun 		break;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	case XGBE_RX_XNP:
597*4882a593Smuzhiyun 		ret = xgbe_an73_rx_xnp(pdata, state);
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	default:
601*4882a593Smuzhiyun 		ret = XGBE_AN_ERROR;
602*4882a593Smuzhiyun 	}
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return ret;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
xgbe_an73_incompat_link(struct xgbe_prv_data * pdata)607*4882a593Smuzhiyun static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	/* Be sure we aren't looping trying to negotiate */
612*4882a593Smuzhiyun 	if (xgbe_in_kr_mode(pdata)) {
613*4882a593Smuzhiyun 		pdata->kr_state = XGBE_RX_ERROR;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 		if (!XGBE_ADV(lks, 1000baseKX_Full) &&
616*4882a593Smuzhiyun 		    !XGBE_ADV(lks, 2500baseX_Full))
617*4882a593Smuzhiyun 			return XGBE_AN_NO_LINK;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 		if (pdata->kx_state != XGBE_RX_BPA)
620*4882a593Smuzhiyun 			return XGBE_AN_NO_LINK;
621*4882a593Smuzhiyun 	} else {
622*4882a593Smuzhiyun 		pdata->kx_state = XGBE_RX_ERROR;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 		if (!XGBE_ADV(lks, 10000baseKR_Full))
625*4882a593Smuzhiyun 			return XGBE_AN_NO_LINK;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 		if (pdata->kr_state != XGBE_RX_BPA)
628*4882a593Smuzhiyun 			return XGBE_AN_NO_LINK;
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	xgbe_an_disable(pdata);
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	xgbe_switch_mode(pdata);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	xgbe_an_restart(pdata);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	return XGBE_AN_INCOMPAT_LINK;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
xgbe_an37_isr(struct xgbe_prv_data * pdata)640*4882a593Smuzhiyun static void xgbe_an37_isr(struct xgbe_prv_data *pdata)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun 	unsigned int reg;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	/* Disable AN interrupts */
645*4882a593Smuzhiyun 	xgbe_an37_disable_interrupts(pdata);
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	/* Save the interrupt(s) that fired */
648*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
649*4882a593Smuzhiyun 	pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
650*4882a593Smuzhiyun 	pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	if (pdata->an_int) {
653*4882a593Smuzhiyun 		/* Clear the interrupt(s) that fired and process them */
654*4882a593Smuzhiyun 		reg &= ~XGBE_AN_CL37_INT_MASK;
655*4882a593Smuzhiyun 		XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 		queue_work(pdata->an_workqueue, &pdata->an_irq_work);
658*4882a593Smuzhiyun 	} else {
659*4882a593Smuzhiyun 		/* Enable AN interrupts */
660*4882a593Smuzhiyun 		xgbe_an37_enable_interrupts(pdata);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 		/* Reissue interrupt if status is not clear */
663*4882a593Smuzhiyun 		if (pdata->vdata->irq_reissue_support)
664*4882a593Smuzhiyun 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
xgbe_an73_isr(struct xgbe_prv_data * pdata)668*4882a593Smuzhiyun static void xgbe_an73_isr(struct xgbe_prv_data *pdata)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	/* Disable AN interrupts */
671*4882a593Smuzhiyun 	xgbe_an73_disable_interrupts(pdata);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	/* Save the interrupt(s) that fired */
674*4882a593Smuzhiyun 	pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (pdata->an_int) {
677*4882a593Smuzhiyun 		/* Clear the interrupt(s) that fired and process them */
678*4882a593Smuzhiyun 		XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 		queue_work(pdata->an_workqueue, &pdata->an_irq_work);
681*4882a593Smuzhiyun 	} else {
682*4882a593Smuzhiyun 		/* Enable AN interrupts */
683*4882a593Smuzhiyun 		xgbe_an73_enable_interrupts(pdata);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 		/* Reissue interrupt if status is not clear */
686*4882a593Smuzhiyun 		if (pdata->vdata->irq_reissue_support)
687*4882a593Smuzhiyun 			XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
xgbe_an_isr_task(struct tasklet_struct * t)691*4882a593Smuzhiyun static void xgbe_an_isr_task(struct tasklet_struct *t)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun 	struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_an);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	switch (pdata->an_mode) {
698*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
699*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
700*4882a593Smuzhiyun 		xgbe_an73_isr(pdata);
701*4882a593Smuzhiyun 		break;
702*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
703*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
704*4882a593Smuzhiyun 		xgbe_an37_isr(pdata);
705*4882a593Smuzhiyun 		break;
706*4882a593Smuzhiyun 	default:
707*4882a593Smuzhiyun 		break;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
xgbe_an_isr(int irq,void * data)711*4882a593Smuzhiyun static irqreturn_t xgbe_an_isr(int irq, void *data)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	if (pdata->isr_as_tasklet)
716*4882a593Smuzhiyun 		tasklet_schedule(&pdata->tasklet_an);
717*4882a593Smuzhiyun 	else
718*4882a593Smuzhiyun 		xgbe_an_isr_task(&pdata->tasklet_an);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	return IRQ_HANDLED;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun 
xgbe_an_combined_isr(struct xgbe_prv_data * pdata)723*4882a593Smuzhiyun static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun 	xgbe_an_isr_task(&pdata->tasklet_an);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	return IRQ_HANDLED;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun 
xgbe_an_irq_work(struct work_struct * work)730*4882a593Smuzhiyun static void xgbe_an_irq_work(struct work_struct *work)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun 	struct xgbe_prv_data *pdata = container_of(work,
733*4882a593Smuzhiyun 						   struct xgbe_prv_data,
734*4882a593Smuzhiyun 						   an_irq_work);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	/* Avoid a race between enabling the IRQ and exiting the work by
737*4882a593Smuzhiyun 	 * waiting for the work to finish and then queueing it
738*4882a593Smuzhiyun 	 */
739*4882a593Smuzhiyun 	flush_work(&pdata->an_work);
740*4882a593Smuzhiyun 	queue_work(pdata->an_workqueue, &pdata->an_work);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
xgbe_state_as_string(enum xgbe_an state)743*4882a593Smuzhiyun static const char *xgbe_state_as_string(enum xgbe_an state)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun 	switch (state) {
746*4882a593Smuzhiyun 	case XGBE_AN_READY:
747*4882a593Smuzhiyun 		return "Ready";
748*4882a593Smuzhiyun 	case XGBE_AN_PAGE_RECEIVED:
749*4882a593Smuzhiyun 		return "Page-Received";
750*4882a593Smuzhiyun 	case XGBE_AN_INCOMPAT_LINK:
751*4882a593Smuzhiyun 		return "Incompatible-Link";
752*4882a593Smuzhiyun 	case XGBE_AN_COMPLETE:
753*4882a593Smuzhiyun 		return "Complete";
754*4882a593Smuzhiyun 	case XGBE_AN_NO_LINK:
755*4882a593Smuzhiyun 		return "No-Link";
756*4882a593Smuzhiyun 	case XGBE_AN_ERROR:
757*4882a593Smuzhiyun 		return "Error";
758*4882a593Smuzhiyun 	default:
759*4882a593Smuzhiyun 		return "Undefined";
760*4882a593Smuzhiyun 	}
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
xgbe_an37_state_machine(struct xgbe_prv_data * pdata)763*4882a593Smuzhiyun static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun 	enum xgbe_an cur_state = pdata->an_state;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	if (!pdata->an_int)
768*4882a593Smuzhiyun 		return;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
771*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_COMPLETE;
772*4882a593Smuzhiyun 		pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 		/* If SGMII is enabled, check the link status */
775*4882a593Smuzhiyun 		if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
776*4882a593Smuzhiyun 		    !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
777*4882a593Smuzhiyun 			pdata->an_state = XGBE_AN_NO_LINK;
778*4882a593Smuzhiyun 	}
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n",
781*4882a593Smuzhiyun 		  xgbe_state_as_string(pdata->an_state));
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	cur_state = pdata->an_state;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	switch (pdata->an_state) {
786*4882a593Smuzhiyun 	case XGBE_AN_READY:
787*4882a593Smuzhiyun 		break;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	case XGBE_AN_COMPLETE:
790*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev,
791*4882a593Smuzhiyun 			  "Auto negotiation successful\n");
792*4882a593Smuzhiyun 		break;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	case XGBE_AN_NO_LINK:
795*4882a593Smuzhiyun 		break;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	default:
798*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_ERROR;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	if (pdata->an_state == XGBE_AN_ERROR) {
802*4882a593Smuzhiyun 		netdev_err(pdata->netdev,
803*4882a593Smuzhiyun 			   "error during auto-negotiation, state=%u\n",
804*4882a593Smuzhiyun 			   cur_state);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 		pdata->an_int = 0;
807*4882a593Smuzhiyun 		xgbe_an37_clear_interrupts(pdata);
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
811*4882a593Smuzhiyun 		pdata->an_result = pdata->an_state;
812*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_READY;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 		if (pdata->phy_if.phy_impl.an_post)
815*4882a593Smuzhiyun 			pdata->phy_if.phy_impl.an_post(pdata);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
818*4882a593Smuzhiyun 			  xgbe_state_as_string(pdata->an_result));
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 	xgbe_an37_enable_interrupts(pdata);
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
xgbe_an73_state_machine(struct xgbe_prv_data * pdata)824*4882a593Smuzhiyun static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	enum xgbe_an cur_state = pdata->an_state;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	if (!pdata->an_int)
829*4882a593Smuzhiyun 		return;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun next_int:
832*4882a593Smuzhiyun 	if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
833*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_PAGE_RECEIVED;
834*4882a593Smuzhiyun 		pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
835*4882a593Smuzhiyun 	} else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
836*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_INCOMPAT_LINK;
837*4882a593Smuzhiyun 		pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
838*4882a593Smuzhiyun 	} else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
839*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_COMPLETE;
840*4882a593Smuzhiyun 		pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
841*4882a593Smuzhiyun 	} else {
842*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_ERROR;
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun again:
846*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n",
847*4882a593Smuzhiyun 		  xgbe_state_as_string(pdata->an_state));
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	cur_state = pdata->an_state;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	switch (pdata->an_state) {
852*4882a593Smuzhiyun 	case XGBE_AN_READY:
853*4882a593Smuzhiyun 		pdata->an_supported = 0;
854*4882a593Smuzhiyun 		break;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	case XGBE_AN_PAGE_RECEIVED:
857*4882a593Smuzhiyun 		pdata->an_state = xgbe_an73_page_received(pdata);
858*4882a593Smuzhiyun 		pdata->an_supported++;
859*4882a593Smuzhiyun 		break;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	case XGBE_AN_INCOMPAT_LINK:
862*4882a593Smuzhiyun 		pdata->an_supported = 0;
863*4882a593Smuzhiyun 		pdata->parallel_detect = 0;
864*4882a593Smuzhiyun 		pdata->an_state = xgbe_an73_incompat_link(pdata);
865*4882a593Smuzhiyun 		break;
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	case XGBE_AN_COMPLETE:
868*4882a593Smuzhiyun 		pdata->parallel_detect = pdata->an_supported ? 0 : 1;
869*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "%s successful\n",
870*4882a593Smuzhiyun 			  pdata->an_supported ? "Auto negotiation"
871*4882a593Smuzhiyun 					      : "Parallel detection");
872*4882a593Smuzhiyun 		break;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	case XGBE_AN_NO_LINK:
875*4882a593Smuzhiyun 		break;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	default:
878*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_ERROR;
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	if (pdata->an_state == XGBE_AN_NO_LINK) {
882*4882a593Smuzhiyun 		pdata->an_int = 0;
883*4882a593Smuzhiyun 		xgbe_an73_clear_interrupts(pdata);
884*4882a593Smuzhiyun 	} else if (pdata->an_state == XGBE_AN_ERROR) {
885*4882a593Smuzhiyun 		netdev_err(pdata->netdev,
886*4882a593Smuzhiyun 			   "error during auto-negotiation, state=%u\n",
887*4882a593Smuzhiyun 			   cur_state);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 		pdata->an_int = 0;
890*4882a593Smuzhiyun 		xgbe_an73_clear_interrupts(pdata);
891*4882a593Smuzhiyun 	}
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	if (pdata->an_state >= XGBE_AN_COMPLETE) {
894*4882a593Smuzhiyun 		pdata->an_result = pdata->an_state;
895*4882a593Smuzhiyun 		pdata->an_state = XGBE_AN_READY;
896*4882a593Smuzhiyun 		pdata->kr_state = XGBE_RX_BPA;
897*4882a593Smuzhiyun 		pdata->kx_state = XGBE_RX_BPA;
898*4882a593Smuzhiyun 		pdata->an_start = 0;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 		if (pdata->phy_if.phy_impl.an_post)
901*4882a593Smuzhiyun 			pdata->phy_if.phy_impl.an_post(pdata);
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
904*4882a593Smuzhiyun 			  xgbe_state_as_string(pdata->an_result));
905*4882a593Smuzhiyun 	}
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	if (cur_state != pdata->an_state)
908*4882a593Smuzhiyun 		goto again;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	if (pdata->an_int)
911*4882a593Smuzhiyun 		goto next_int;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	xgbe_an73_enable_interrupts(pdata);
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun 
xgbe_an_state_machine(struct work_struct * work)916*4882a593Smuzhiyun static void xgbe_an_state_machine(struct work_struct *work)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun 	struct xgbe_prv_data *pdata = container_of(work,
919*4882a593Smuzhiyun 						   struct xgbe_prv_data,
920*4882a593Smuzhiyun 						   an_work);
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	mutex_lock(&pdata->an_mutex);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	switch (pdata->an_mode) {
925*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
926*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
927*4882a593Smuzhiyun 		xgbe_an73_state_machine(pdata);
928*4882a593Smuzhiyun 		break;
929*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
930*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
931*4882a593Smuzhiyun 		xgbe_an37_state_machine(pdata);
932*4882a593Smuzhiyun 		break;
933*4882a593Smuzhiyun 	default:
934*4882a593Smuzhiyun 		break;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	/* Reissue interrupt if status is not clear */
938*4882a593Smuzhiyun 	if (pdata->vdata->irq_reissue_support)
939*4882a593Smuzhiyun 		XP_IOWRITE(pdata, XP_INT_REISSUE_EN, 1 << 3);
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	mutex_unlock(&pdata->an_mutex);
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun 
xgbe_an37_init(struct xgbe_prv_data * pdata)944*4882a593Smuzhiyun static void xgbe_an37_init(struct xgbe_prv_data *pdata)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun 	struct ethtool_link_ksettings lks;
947*4882a593Smuzhiyun 	unsigned int reg;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	/* Set up Advertisement register */
952*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
953*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, Pause))
954*4882a593Smuzhiyun 		reg |= 0x100;
955*4882a593Smuzhiyun 	else
956*4882a593Smuzhiyun 		reg &= ~0x100;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, Asym_Pause))
959*4882a593Smuzhiyun 		reg |= 0x80;
960*4882a593Smuzhiyun 	else
961*4882a593Smuzhiyun 		reg &= ~0x80;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	/* Full duplex, but not half */
964*4882a593Smuzhiyun 	reg |= XGBE_AN_CL37_FD_MASK;
965*4882a593Smuzhiyun 	reg &= ~XGBE_AN_CL37_HD_MASK;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	/* Set up the Control register */
970*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
971*4882a593Smuzhiyun 	reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK;
972*4882a593Smuzhiyun 	reg &= ~XGBE_AN_CL37_PCS_MODE_MASK;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	switch (pdata->an_mode) {
975*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
976*4882a593Smuzhiyun 		reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
977*4882a593Smuzhiyun 		break;
978*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
979*4882a593Smuzhiyun 		reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
980*4882a593Smuzhiyun 		break;
981*4882a593Smuzhiyun 	default:
982*4882a593Smuzhiyun 		break;
983*4882a593Smuzhiyun 	}
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	reg |= XGBE_AN_CL37_MII_CTRL_8BIT;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n",
990*4882a593Smuzhiyun 		  (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
xgbe_an73_init(struct xgbe_prv_data * pdata)993*4882a593Smuzhiyun static void xgbe_an73_init(struct xgbe_prv_data *pdata)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun 	struct ethtool_link_ksettings lks;
996*4882a593Smuzhiyun 	unsigned int reg;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.an_advertising(pdata, &lks);
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	/* Set up Advertisement register 3 first */
1001*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
1002*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, 10000baseR_FEC))
1003*4882a593Smuzhiyun 		reg |= 0xc000;
1004*4882a593Smuzhiyun 	else
1005*4882a593Smuzhiyun 		reg &= ~0xc000;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	/* Set up Advertisement register 2 next */
1010*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
1011*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, 10000baseKR_Full))
1012*4882a593Smuzhiyun 		reg |= 0x80;
1013*4882a593Smuzhiyun 	else
1014*4882a593Smuzhiyun 		reg &= ~0x80;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, 1000baseKX_Full) ||
1017*4882a593Smuzhiyun 	    XGBE_ADV(&lks, 2500baseX_Full))
1018*4882a593Smuzhiyun 		reg |= 0x20;
1019*4882a593Smuzhiyun 	else
1020*4882a593Smuzhiyun 		reg &= ~0x20;
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	/* Set up Advertisement register 1 last */
1025*4882a593Smuzhiyun 	reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
1026*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, Pause))
1027*4882a593Smuzhiyun 		reg |= 0x400;
1028*4882a593Smuzhiyun 	else
1029*4882a593Smuzhiyun 		reg &= ~0x400;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (XGBE_ADV(&lks, Asym_Pause))
1032*4882a593Smuzhiyun 		reg |= 0x800;
1033*4882a593Smuzhiyun 	else
1034*4882a593Smuzhiyun 		reg &= ~0x800;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	/* We don't intend to perform XNP */
1037*4882a593Smuzhiyun 	reg &= ~XGBE_XNP_NP_EXCHANGE;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n");
1042*4882a593Smuzhiyun }
1043*4882a593Smuzhiyun 
xgbe_an_init(struct xgbe_prv_data * pdata)1044*4882a593Smuzhiyun static void xgbe_an_init(struct xgbe_prv_data *pdata)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun 	/* Set up advertisement registers based on current settings */
1047*4882a593Smuzhiyun 	pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
1048*4882a593Smuzhiyun 	switch (pdata->an_mode) {
1049*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73:
1050*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL73_REDRV:
1051*4882a593Smuzhiyun 		xgbe_an73_init(pdata);
1052*4882a593Smuzhiyun 		break;
1053*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37:
1054*4882a593Smuzhiyun 	case XGBE_AN_MODE_CL37_SGMII:
1055*4882a593Smuzhiyun 		xgbe_an37_init(pdata);
1056*4882a593Smuzhiyun 		break;
1057*4882a593Smuzhiyun 	default:
1058*4882a593Smuzhiyun 		break;
1059*4882a593Smuzhiyun 	}
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun 
xgbe_phy_fc_string(struct xgbe_prv_data * pdata)1062*4882a593Smuzhiyun static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun 	if (pdata->tx_pause && pdata->rx_pause)
1065*4882a593Smuzhiyun 		return "rx/tx";
1066*4882a593Smuzhiyun 	else if (pdata->rx_pause)
1067*4882a593Smuzhiyun 		return "rx";
1068*4882a593Smuzhiyun 	else if (pdata->tx_pause)
1069*4882a593Smuzhiyun 		return "tx";
1070*4882a593Smuzhiyun 	else
1071*4882a593Smuzhiyun 		return "off";
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
xgbe_phy_speed_string(int speed)1074*4882a593Smuzhiyun static const char *xgbe_phy_speed_string(int speed)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun 	switch (speed) {
1077*4882a593Smuzhiyun 	case SPEED_100:
1078*4882a593Smuzhiyun 		return "100Mbps";
1079*4882a593Smuzhiyun 	case SPEED_1000:
1080*4882a593Smuzhiyun 		return "1Gbps";
1081*4882a593Smuzhiyun 	case SPEED_2500:
1082*4882a593Smuzhiyun 		return "2.5Gbps";
1083*4882a593Smuzhiyun 	case SPEED_10000:
1084*4882a593Smuzhiyun 		return "10Gbps";
1085*4882a593Smuzhiyun 	case SPEED_UNKNOWN:
1086*4882a593Smuzhiyun 		return "Unknown";
1087*4882a593Smuzhiyun 	default:
1088*4882a593Smuzhiyun 		return "Unsupported";
1089*4882a593Smuzhiyun 	}
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun 
xgbe_phy_print_status(struct xgbe_prv_data * pdata)1092*4882a593Smuzhiyun static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun 	if (pdata->phy.link)
1095*4882a593Smuzhiyun 		netdev_info(pdata->netdev,
1096*4882a593Smuzhiyun 			    "Link is Up - %s/%s - flow control %s\n",
1097*4882a593Smuzhiyun 			    xgbe_phy_speed_string(pdata->phy.speed),
1098*4882a593Smuzhiyun 			    pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
1099*4882a593Smuzhiyun 			    xgbe_phy_fc_string(pdata));
1100*4882a593Smuzhiyun 	else
1101*4882a593Smuzhiyun 		netdev_info(pdata->netdev, "Link is Down\n");
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun 
xgbe_phy_adjust_link(struct xgbe_prv_data * pdata)1104*4882a593Smuzhiyun static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
1105*4882a593Smuzhiyun {
1106*4882a593Smuzhiyun 	int new_state = 0;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	if (pdata->phy.link) {
1109*4882a593Smuzhiyun 		/* Flow control support */
1110*4882a593Smuzhiyun 		pdata->pause_autoneg = pdata->phy.pause_autoneg;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 		if (pdata->tx_pause != pdata->phy.tx_pause) {
1113*4882a593Smuzhiyun 			new_state = 1;
1114*4882a593Smuzhiyun 			pdata->tx_pause = pdata->phy.tx_pause;
1115*4882a593Smuzhiyun 			pdata->hw_if.config_tx_flow_control(pdata);
1116*4882a593Smuzhiyun 		}
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 		if (pdata->rx_pause != pdata->phy.rx_pause) {
1119*4882a593Smuzhiyun 			new_state = 1;
1120*4882a593Smuzhiyun 			pdata->rx_pause = pdata->phy.rx_pause;
1121*4882a593Smuzhiyun 			pdata->hw_if.config_rx_flow_control(pdata);
1122*4882a593Smuzhiyun 		}
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 		/* Speed support */
1125*4882a593Smuzhiyun 		if (pdata->phy_speed != pdata->phy.speed) {
1126*4882a593Smuzhiyun 			new_state = 1;
1127*4882a593Smuzhiyun 			pdata->phy_speed = pdata->phy.speed;
1128*4882a593Smuzhiyun 		}
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 		if (pdata->phy_link != pdata->phy.link) {
1131*4882a593Smuzhiyun 			new_state = 1;
1132*4882a593Smuzhiyun 			pdata->phy_link = pdata->phy.link;
1133*4882a593Smuzhiyun 		}
1134*4882a593Smuzhiyun 	} else if (pdata->phy_link) {
1135*4882a593Smuzhiyun 		new_state = 1;
1136*4882a593Smuzhiyun 		pdata->phy_link = 0;
1137*4882a593Smuzhiyun 		pdata->phy_speed = SPEED_UNKNOWN;
1138*4882a593Smuzhiyun 	}
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	if (new_state && netif_msg_link(pdata))
1141*4882a593Smuzhiyun 		xgbe_phy_print_status(pdata);
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun 
xgbe_phy_valid_speed(struct xgbe_prv_data * pdata,int speed)1144*4882a593Smuzhiyun static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.valid_speed(pdata, speed);
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun 
xgbe_phy_config_fixed(struct xgbe_prv_data * pdata)1149*4882a593Smuzhiyun static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
1150*4882a593Smuzhiyun {
1151*4882a593Smuzhiyun 	enum xgbe_mode mode;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	/* Disable auto-negotiation */
1156*4882a593Smuzhiyun 	xgbe_an_disable(pdata);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	/* Set specified mode for specified speed */
1159*4882a593Smuzhiyun 	mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
1160*4882a593Smuzhiyun 	switch (mode) {
1161*4882a593Smuzhiyun 	case XGBE_MODE_KX_1000:
1162*4882a593Smuzhiyun 	case XGBE_MODE_KX_2500:
1163*4882a593Smuzhiyun 	case XGBE_MODE_KR:
1164*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_100:
1165*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_1000:
1166*4882a593Smuzhiyun 	case XGBE_MODE_X:
1167*4882a593Smuzhiyun 	case XGBE_MODE_SFI:
1168*4882a593Smuzhiyun 		break;
1169*4882a593Smuzhiyun 	case XGBE_MODE_UNKNOWN:
1170*4882a593Smuzhiyun 	default:
1171*4882a593Smuzhiyun 		return -EINVAL;
1172*4882a593Smuzhiyun 	}
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	/* Validate duplex mode */
1175*4882a593Smuzhiyun 	if (pdata->phy.duplex != DUPLEX_FULL)
1176*4882a593Smuzhiyun 		return -EINVAL;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	xgbe_set_mode(pdata, mode);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	return 0;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun 
__xgbe_phy_config_aneg(struct xgbe_prv_data * pdata,bool set_mode)1183*4882a593Smuzhiyun static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata, bool set_mode)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun 	int ret;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	mutex_lock(&pdata->an_mutex);
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	set_bit(XGBE_LINK_INIT, &pdata->dev_state);
1190*4882a593Smuzhiyun 	pdata->link_check = jiffies;
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	ret = pdata->phy_if.phy_impl.an_config(pdata);
1193*4882a593Smuzhiyun 	if (ret)
1194*4882a593Smuzhiyun 		goto out;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	if (pdata->phy.autoneg != AUTONEG_ENABLE) {
1197*4882a593Smuzhiyun 		ret = xgbe_phy_config_fixed(pdata);
1198*4882a593Smuzhiyun 		if (ret || !pdata->kr_redrv)
1199*4882a593Smuzhiyun 			goto out;
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n");
1202*4882a593Smuzhiyun 	} else {
1203*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
1204*4882a593Smuzhiyun 	}
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	/* Disable auto-negotiation interrupt */
1207*4882a593Smuzhiyun 	disable_irq(pdata->an_irq);
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	if (set_mode) {
1210*4882a593Smuzhiyun 		/* Start auto-negotiation in a supported mode */
1211*4882a593Smuzhiyun 		if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1212*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_KR);
1213*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1214*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1215*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1216*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
1217*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
1218*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_SFI);
1219*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
1220*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_X);
1221*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
1222*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000);
1223*4882a593Smuzhiyun 		} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
1224*4882a593Smuzhiyun 			xgbe_set_mode(pdata, XGBE_MODE_SGMII_100);
1225*4882a593Smuzhiyun 		} else {
1226*4882a593Smuzhiyun 			enable_irq(pdata->an_irq);
1227*4882a593Smuzhiyun 			ret = -EINVAL;
1228*4882a593Smuzhiyun 			goto out;
1229*4882a593Smuzhiyun 		}
1230*4882a593Smuzhiyun 	}
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	/* Disable and stop any in progress auto-negotiation */
1233*4882a593Smuzhiyun 	xgbe_an_disable_all(pdata);
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	/* Clear any auto-negotitation interrupts */
1236*4882a593Smuzhiyun 	xgbe_an_clear_interrupts_all(pdata);
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	pdata->an_result = XGBE_AN_READY;
1239*4882a593Smuzhiyun 	pdata->an_state = XGBE_AN_READY;
1240*4882a593Smuzhiyun 	pdata->kr_state = XGBE_RX_BPA;
1241*4882a593Smuzhiyun 	pdata->kx_state = XGBE_RX_BPA;
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	/* Re-enable auto-negotiation interrupt */
1244*4882a593Smuzhiyun 	enable_irq(pdata->an_irq);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	xgbe_an_init(pdata);
1247*4882a593Smuzhiyun 	xgbe_an_restart(pdata);
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun out:
1250*4882a593Smuzhiyun 	if (ret)
1251*4882a593Smuzhiyun 		set_bit(XGBE_LINK_ERR, &pdata->dev_state);
1252*4882a593Smuzhiyun 	else
1253*4882a593Smuzhiyun 		clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	mutex_unlock(&pdata->an_mutex);
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	return ret;
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun 
xgbe_phy_config_aneg(struct xgbe_prv_data * pdata)1260*4882a593Smuzhiyun static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	return __xgbe_phy_config_aneg(pdata, true);
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
xgbe_phy_reconfig_aneg(struct xgbe_prv_data * pdata)1265*4882a593Smuzhiyun static int xgbe_phy_reconfig_aneg(struct xgbe_prv_data *pdata)
1266*4882a593Smuzhiyun {
1267*4882a593Smuzhiyun 	return __xgbe_phy_config_aneg(pdata, false);
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun 
xgbe_phy_aneg_done(struct xgbe_prv_data * pdata)1270*4882a593Smuzhiyun static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
1271*4882a593Smuzhiyun {
1272*4882a593Smuzhiyun 	return (pdata->an_result == XGBE_AN_COMPLETE);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun 
xgbe_check_link_timeout(struct xgbe_prv_data * pdata)1275*4882a593Smuzhiyun static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun 	unsigned long link_timeout;
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
1280*4882a593Smuzhiyun 	if (time_after(jiffies, link_timeout)) {
1281*4882a593Smuzhiyun 		netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
1282*4882a593Smuzhiyun 		xgbe_phy_config_aneg(pdata);
1283*4882a593Smuzhiyun 	}
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
xgbe_phy_status_aneg(struct xgbe_prv_data * pdata)1286*4882a593Smuzhiyun static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun 	return pdata->phy_if.phy_impl.an_outcome(pdata);
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun 
xgbe_phy_status_result(struct xgbe_prv_data * pdata)1291*4882a593Smuzhiyun static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
1292*4882a593Smuzhiyun {
1293*4882a593Smuzhiyun 	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
1294*4882a593Smuzhiyun 	enum xgbe_mode mode;
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	XGBE_ZERO_LP_ADV(lks);
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
1299*4882a593Smuzhiyun 		mode = xgbe_cur_mode(pdata);
1300*4882a593Smuzhiyun 	else
1301*4882a593Smuzhiyun 		mode = xgbe_phy_status_aneg(pdata);
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	switch (mode) {
1304*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_100:
1305*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_100;
1306*4882a593Smuzhiyun 		break;
1307*4882a593Smuzhiyun 	case XGBE_MODE_X:
1308*4882a593Smuzhiyun 	case XGBE_MODE_KX_1000:
1309*4882a593Smuzhiyun 	case XGBE_MODE_SGMII_1000:
1310*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_1000;
1311*4882a593Smuzhiyun 		break;
1312*4882a593Smuzhiyun 	case XGBE_MODE_KX_2500:
1313*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_2500;
1314*4882a593Smuzhiyun 		break;
1315*4882a593Smuzhiyun 	case XGBE_MODE_KR:
1316*4882a593Smuzhiyun 	case XGBE_MODE_SFI:
1317*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_10000;
1318*4882a593Smuzhiyun 		break;
1319*4882a593Smuzhiyun 	case XGBE_MODE_UNKNOWN:
1320*4882a593Smuzhiyun 	default:
1321*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_UNKNOWN;
1322*4882a593Smuzhiyun 	}
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	pdata->phy.duplex = DUPLEX_FULL;
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	if (xgbe_set_mode(pdata, mode) && pdata->an_again)
1327*4882a593Smuzhiyun 		xgbe_phy_reconfig_aneg(pdata);
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun 
xgbe_phy_status(struct xgbe_prv_data * pdata)1330*4882a593Smuzhiyun static void xgbe_phy_status(struct xgbe_prv_data *pdata)
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun 	unsigned int link_aneg;
1333*4882a593Smuzhiyun 	int an_restart;
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun 	if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
1336*4882a593Smuzhiyun 		netif_carrier_off(pdata->netdev);
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 		pdata->phy.link = 0;
1339*4882a593Smuzhiyun 		goto adjust_link;
1340*4882a593Smuzhiyun 	}
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata,
1345*4882a593Smuzhiyun 							     &an_restart);
1346*4882a593Smuzhiyun 	if (an_restart) {
1347*4882a593Smuzhiyun 		xgbe_phy_config_aneg(pdata);
1348*4882a593Smuzhiyun 		goto adjust_link;
1349*4882a593Smuzhiyun 	}
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	if (pdata->phy.link) {
1352*4882a593Smuzhiyun 		if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
1353*4882a593Smuzhiyun 			xgbe_check_link_timeout(pdata);
1354*4882a593Smuzhiyun 			return;
1355*4882a593Smuzhiyun 		}
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 		xgbe_phy_status_result(pdata);
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
1360*4882a593Smuzhiyun 			clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun 		netif_carrier_on(pdata->netdev);
1363*4882a593Smuzhiyun 	} else {
1364*4882a593Smuzhiyun 		if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
1365*4882a593Smuzhiyun 			xgbe_check_link_timeout(pdata);
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 			if (link_aneg)
1368*4882a593Smuzhiyun 				return;
1369*4882a593Smuzhiyun 		}
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 		xgbe_phy_status_result(pdata);
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 		netif_carrier_off(pdata->netdev);
1374*4882a593Smuzhiyun 	}
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun adjust_link:
1377*4882a593Smuzhiyun 	xgbe_phy_adjust_link(pdata);
1378*4882a593Smuzhiyun }
1379*4882a593Smuzhiyun 
xgbe_phy_stop(struct xgbe_prv_data * pdata)1380*4882a593Smuzhiyun static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n");
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	if (!pdata->phy_started)
1385*4882a593Smuzhiyun 		return;
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun 	/* Indicate the PHY is down */
1388*4882a593Smuzhiyun 	pdata->phy_started = 0;
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	/* Disable auto-negotiation */
1391*4882a593Smuzhiyun 	xgbe_an_disable_all(pdata);
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	if (pdata->dev_irq != pdata->an_irq)
1394*4882a593Smuzhiyun 		devm_free_irq(pdata->dev, pdata->an_irq, pdata);
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.stop(pdata);
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	pdata->phy.link = 0;
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	xgbe_phy_adjust_link(pdata);
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun 
xgbe_phy_start(struct xgbe_prv_data * pdata)1403*4882a593Smuzhiyun static int xgbe_phy_start(struct xgbe_prv_data *pdata)
1404*4882a593Smuzhiyun {
1405*4882a593Smuzhiyun 	struct net_device *netdev = pdata->netdev;
1406*4882a593Smuzhiyun 	int ret;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	netif_dbg(pdata, link, pdata->netdev, "starting PHY\n");
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	ret = pdata->phy_if.phy_impl.start(pdata);
1411*4882a593Smuzhiyun 	if (ret)
1412*4882a593Smuzhiyun 		return ret;
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun 	/* If we have a separate AN irq, enable it */
1415*4882a593Smuzhiyun 	if (pdata->dev_irq != pdata->an_irq) {
1416*4882a593Smuzhiyun 		tasklet_setup(&pdata->tasklet_an, xgbe_an_isr_task);
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 		ret = devm_request_irq(pdata->dev, pdata->an_irq,
1419*4882a593Smuzhiyun 				       xgbe_an_isr, 0, pdata->an_name,
1420*4882a593Smuzhiyun 				       pdata);
1421*4882a593Smuzhiyun 		if (ret) {
1422*4882a593Smuzhiyun 			netdev_err(netdev, "phy irq request failed\n");
1423*4882a593Smuzhiyun 			goto err_stop;
1424*4882a593Smuzhiyun 		}
1425*4882a593Smuzhiyun 	}
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	/* Set initial mode - call the mode setting routines
1428*4882a593Smuzhiyun 	 * directly to insure we are properly configured
1429*4882a593Smuzhiyun 	 */
1430*4882a593Smuzhiyun 	if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1431*4882a593Smuzhiyun 		xgbe_kr_mode(pdata);
1432*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1433*4882a593Smuzhiyun 		xgbe_kx_2500_mode(pdata);
1434*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1435*4882a593Smuzhiyun 		xgbe_kx_1000_mode(pdata);
1436*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) {
1437*4882a593Smuzhiyun 		xgbe_sfi_mode(pdata);
1438*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_X)) {
1439*4882a593Smuzhiyun 		xgbe_x_mode(pdata);
1440*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) {
1441*4882a593Smuzhiyun 		xgbe_sgmii_1000_mode(pdata);
1442*4882a593Smuzhiyun 	} else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) {
1443*4882a593Smuzhiyun 		xgbe_sgmii_100_mode(pdata);
1444*4882a593Smuzhiyun 	} else {
1445*4882a593Smuzhiyun 		ret = -EINVAL;
1446*4882a593Smuzhiyun 		goto err_irq;
1447*4882a593Smuzhiyun 	}
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	/* Indicate the PHY is up and running */
1450*4882a593Smuzhiyun 	pdata->phy_started = 1;
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	xgbe_an_init(pdata);
1453*4882a593Smuzhiyun 	xgbe_an_enable_interrupts(pdata);
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 	return xgbe_phy_config_aneg(pdata);
1456*4882a593Smuzhiyun 
1457*4882a593Smuzhiyun err_irq:
1458*4882a593Smuzhiyun 	if (pdata->dev_irq != pdata->an_irq)
1459*4882a593Smuzhiyun 		devm_free_irq(pdata->dev, pdata->an_irq, pdata);
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun err_stop:
1462*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.stop(pdata);
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	return ret;
1465*4882a593Smuzhiyun }
1466*4882a593Smuzhiyun 
xgbe_phy_reset(struct xgbe_prv_data * pdata)1467*4882a593Smuzhiyun static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
1468*4882a593Smuzhiyun {
1469*4882a593Smuzhiyun 	int ret;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	ret = pdata->phy_if.phy_impl.reset(pdata);
1472*4882a593Smuzhiyun 	if (ret)
1473*4882a593Smuzhiyun 		return ret;
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	/* Disable auto-negotiation for now */
1476*4882a593Smuzhiyun 	xgbe_an_disable_all(pdata);
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 	/* Clear auto-negotiation interrupts */
1479*4882a593Smuzhiyun 	xgbe_an_clear_interrupts_all(pdata);
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	return 0;
1482*4882a593Smuzhiyun }
1483*4882a593Smuzhiyun 
xgbe_dump_phy_registers(struct xgbe_prv_data * pdata)1484*4882a593Smuzhiyun static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
1485*4882a593Smuzhiyun {
1486*4882a593Smuzhiyun 	struct device *dev = pdata->dev;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	dev_dbg(dev, "\n************* PHY Reg dump **********************\n");
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	dev_dbg(dev, "PCS Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
1491*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
1492*4882a593Smuzhiyun 	dev_dbg(dev, "PCS Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
1493*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
1494*4882a593Smuzhiyun 	dev_dbg(dev, "Phy Id (PHYS ID 1 %#06x)= %#06x\n", MDIO_DEVID1,
1495*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
1496*4882a593Smuzhiyun 	dev_dbg(dev, "Phy Id (PHYS ID 2 %#06x)= %#06x\n", MDIO_DEVID2,
1497*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
1498*4882a593Smuzhiyun 	dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS1,
1499*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
1500*4882a593Smuzhiyun 	dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS2,
1501*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
1504*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
1505*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
1506*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
1507*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#06x) = %#06x\n",
1508*4882a593Smuzhiyun 		MDIO_AN_ADVERTISE,
1509*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
1510*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#06x) = %#06x\n",
1511*4882a593Smuzhiyun 		MDIO_AN_ADVERTISE + 1,
1512*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
1513*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#06x) = %#06x\n",
1514*4882a593Smuzhiyun 		MDIO_AN_ADVERTISE + 2,
1515*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
1516*4882a593Smuzhiyun 	dev_dbg(dev, "Auto-Neg Completion Reg (%#06x) = %#06x\n",
1517*4882a593Smuzhiyun 		MDIO_AN_COMP_STAT,
1518*4882a593Smuzhiyun 		XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 	dev_dbg(dev, "\n*************************************************\n");
1521*4882a593Smuzhiyun }
1522*4882a593Smuzhiyun 
xgbe_phy_best_advertised_speed(struct xgbe_prv_data * pdata)1523*4882a593Smuzhiyun static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
1524*4882a593Smuzhiyun {
1525*4882a593Smuzhiyun 	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	if (XGBE_ADV(lks, 10000baseKR_Full))
1528*4882a593Smuzhiyun 		return SPEED_10000;
1529*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 10000baseT_Full))
1530*4882a593Smuzhiyun 		return SPEED_10000;
1531*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 2500baseX_Full))
1532*4882a593Smuzhiyun 		return SPEED_2500;
1533*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 2500baseT_Full))
1534*4882a593Smuzhiyun 		return SPEED_2500;
1535*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 1000baseKX_Full))
1536*4882a593Smuzhiyun 		return SPEED_1000;
1537*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 1000baseT_Full))
1538*4882a593Smuzhiyun 		return SPEED_1000;
1539*4882a593Smuzhiyun 	else if (XGBE_ADV(lks, 100baseT_Full))
1540*4882a593Smuzhiyun 		return SPEED_100;
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	return SPEED_UNKNOWN;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun 
xgbe_phy_exit(struct xgbe_prv_data * pdata)1545*4882a593Smuzhiyun static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
1546*4882a593Smuzhiyun {
1547*4882a593Smuzhiyun 	pdata->phy_if.phy_impl.exit(pdata);
1548*4882a593Smuzhiyun }
1549*4882a593Smuzhiyun 
xgbe_phy_init(struct xgbe_prv_data * pdata)1550*4882a593Smuzhiyun static int xgbe_phy_init(struct xgbe_prv_data *pdata)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun 	struct ethtool_link_ksettings *lks = &pdata->phy.lks;
1553*4882a593Smuzhiyun 	int ret;
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 	mutex_init(&pdata->an_mutex);
1556*4882a593Smuzhiyun 	INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work);
1557*4882a593Smuzhiyun 	INIT_WORK(&pdata->an_work, xgbe_an_state_machine);
1558*4882a593Smuzhiyun 	pdata->mdio_mmd = MDIO_MMD_PCS;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	/* Check for FEC support */
1561*4882a593Smuzhiyun 	pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
1562*4882a593Smuzhiyun 					MDIO_PMA_10GBR_FECABLE);
1563*4882a593Smuzhiyun 	pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
1564*4882a593Smuzhiyun 			       MDIO_PMA_10GBR_FECABLE_ERRABLE);
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	/* Setup the phy (including supported features) */
1567*4882a593Smuzhiyun 	ret = pdata->phy_if.phy_impl.init(pdata);
1568*4882a593Smuzhiyun 	if (ret)
1569*4882a593Smuzhiyun 		return ret;
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	/* Copy supported link modes to advertising link modes */
1572*4882a593Smuzhiyun 	XGBE_LM_COPY(lks, advertising, lks, supported);
1573*4882a593Smuzhiyun 
1574*4882a593Smuzhiyun 	pdata->phy.address = 0;
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun 	if (XGBE_ADV(lks, Autoneg)) {
1577*4882a593Smuzhiyun 		pdata->phy.autoneg = AUTONEG_ENABLE;
1578*4882a593Smuzhiyun 		pdata->phy.speed = SPEED_UNKNOWN;
1579*4882a593Smuzhiyun 		pdata->phy.duplex = DUPLEX_UNKNOWN;
1580*4882a593Smuzhiyun 	} else {
1581*4882a593Smuzhiyun 		pdata->phy.autoneg = AUTONEG_DISABLE;
1582*4882a593Smuzhiyun 		pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
1583*4882a593Smuzhiyun 		pdata->phy.duplex = DUPLEX_FULL;
1584*4882a593Smuzhiyun 	}
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	pdata->phy.link = 0;
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun 	pdata->phy.pause_autoneg = pdata->pause_autoneg;
1589*4882a593Smuzhiyun 	pdata->phy.tx_pause = pdata->tx_pause;
1590*4882a593Smuzhiyun 	pdata->phy.rx_pause = pdata->rx_pause;
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun 	/* Fix up Flow Control advertising */
1593*4882a593Smuzhiyun 	XGBE_CLR_ADV(lks, Pause);
1594*4882a593Smuzhiyun 	XGBE_CLR_ADV(lks, Asym_Pause);
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	if (pdata->rx_pause) {
1597*4882a593Smuzhiyun 		XGBE_SET_ADV(lks, Pause);
1598*4882a593Smuzhiyun 		XGBE_SET_ADV(lks, Asym_Pause);
1599*4882a593Smuzhiyun 	}
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	if (pdata->tx_pause) {
1602*4882a593Smuzhiyun 		/* Equivalent to XOR of Asym_Pause */
1603*4882a593Smuzhiyun 		if (XGBE_ADV(lks, Asym_Pause))
1604*4882a593Smuzhiyun 			XGBE_CLR_ADV(lks, Asym_Pause);
1605*4882a593Smuzhiyun 		else
1606*4882a593Smuzhiyun 			XGBE_SET_ADV(lks, Asym_Pause);
1607*4882a593Smuzhiyun 	}
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	if (netif_msg_drv(pdata))
1610*4882a593Smuzhiyun 		xgbe_dump_phy_registers(pdata);
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	return 0;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun 
xgbe_init_function_ptrs_phy(struct xgbe_phy_if * phy_if)1615*4882a593Smuzhiyun void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
1616*4882a593Smuzhiyun {
1617*4882a593Smuzhiyun 	phy_if->phy_init        = xgbe_phy_init;
1618*4882a593Smuzhiyun 	phy_if->phy_exit        = xgbe_phy_exit;
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	phy_if->phy_reset       = xgbe_phy_reset;
1621*4882a593Smuzhiyun 	phy_if->phy_start       = xgbe_phy_start;
1622*4882a593Smuzhiyun 	phy_if->phy_stop        = xgbe_phy_stop;
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	phy_if->phy_status      = xgbe_phy_status;
1625*4882a593Smuzhiyun 	phy_if->phy_config_aneg = xgbe_phy_config_aneg;
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 	phy_if->phy_valid_speed = xgbe_phy_valid_speed;
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	phy_if->an_isr          = xgbe_an_combined_isr;
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun 	phy_if->module_info     = xgbe_phy_module_info;
1632*4882a593Smuzhiyun 	phy_if->module_eeprom   = xgbe_phy_module_eeprom;
1633*4882a593Smuzhiyun }
1634