blob: 723eb908b26232b2579dcd28848f46b91def6629 [file] [log] [blame]
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001/*
2 * AMD 10Gb Ethernet driver
3 *
4 * This file is available to you under your choice of the following two
5 * licenses:
6 *
7 * License 1: GPLv2
8 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -06009 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050010 *
11 * This file is free software; you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * This file incorporates work covered by the following copyright and
25 * permission notice:
26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
28 * Inc. unless otherwise expressly agreed to in writing between Synopsys
29 * and you.
30 *
31 * The Software IS NOT an item of Licensed Software or Licensed Product
32 * under any End User Software License Agreement or Agreement for Licensed
33 * Product with Synopsys or any supplement thereto. Permission is hereby
34 * granted, free of charge, to any person obtaining a copy of this software
35 * annotated with this license and the Software, to deal in the Software
36 * without restriction, including without limitation the rights to use,
37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
38 * of the Software, and to permit persons to whom the Software is furnished
39 * to do so, subject to the following conditions:
40 *
41 * The above copyright notice and this permission notice shall be included
42 * in all copies or substantial portions of the Software.
43 *
44 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
45 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 *
57 * License 2: Modified BSD
58 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -060059 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050060 * All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions are met:
64 * * Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * * Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * * Neither the name of Advanced Micro Devices, Inc. nor the
70 * names of its contributors may be used to endorse or promote products
71 * derived from this software without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
74 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83 *
84 * This file incorporates work covered by the following copyright and
85 * permission notice:
86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
88 * Inc. unless otherwise expressly agreed to in writing between Synopsys
89 * and you.
90 *
91 * The Software IS NOT an item of Licensed Software or Licensed Product
92 * under any End User Software License Agreement or Agreement for Licensed
93 * Product with Synopsys or any supplement thereto. Permission is hereby
94 * granted, free of charge, to any person obtaining a copy of this software
95 * annotated with this license and the Software, to deal in the Software
96 * without restriction, including without limitation the rights to use,
97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98 * of the Software, and to permit persons to whom the Software is furnished
99 * to do so, subject to the following conditions:
100 *
101 * The above copyright notice and this permission notice shall be included
102 * in all copies or substantial portions of the Software.
103 *
104 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
105 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
114 * THE POSSIBILITY OF SUCH DAMAGE.
115 */
116
117#include <linux/module.h>
118#include <linux/kmod.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500119#include <linux/mdio.h>
120#include <linux/phy.h>
121#include <linux/of.h>
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500122#include <linux/bitops.h>
123#include <linux/jiffies.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500124
125#include "xgbe.h"
126#include "xgbe-common.h"
127
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500128static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata)
129{
130 int reg;
131
132 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
133 reg &= ~XGBE_AN_CL37_INT_MASK;
134 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
135}
136
137static void xgbe_an37_disable_interrupts(struct xgbe_prv_data *pdata)
138{
139 int reg;
140
141 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
142 reg &= ~XGBE_AN_CL37_INT_MASK;
143 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
144
145 reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
146 reg &= ~XGBE_PCS_CL37_BP;
147 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
148}
149
150static void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata)
151{
152 int reg;
153
154 reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL);
155 reg |= XGBE_PCS_CL37_BP;
156 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg);
157
158 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
159 reg |= XGBE_AN_CL37_INT_MASK;
160 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
161}
162
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500163static void xgbe_an73_clear_interrupts(struct xgbe_prv_data *pdata)
164{
165 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
166}
167
168static void xgbe_an73_disable_interrupts(struct xgbe_prv_data *pdata)
169{
170 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
171}
172
173static void xgbe_an73_enable_interrupts(struct xgbe_prv_data *pdata)
174{
175 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_CL73_INT_MASK);
176}
177
178static void xgbe_an_enable_interrupts(struct xgbe_prv_data *pdata)
179{
180 switch (pdata->an_mode) {
181 case XGBE_AN_MODE_CL73:
182 xgbe_an73_enable_interrupts(pdata);
183 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500184 case XGBE_AN_MODE_CL37:
185 case XGBE_AN_MODE_CL37_SGMII:
186 xgbe_an37_enable_interrupts(pdata);
187 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500188 default:
189 break;
190 }
191}
192
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500193static void xgbe_an_clear_interrupts_all(struct xgbe_prv_data *pdata)
194{
195 xgbe_an73_clear_interrupts(pdata);
196 xgbe_an37_clear_interrupts(pdata);
197}
198
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500199static void xgbe_an73_enable_kr_training(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500200{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500201 unsigned int reg;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500202
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500203 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500204
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500205 reg |= XGBE_KR_TRAINING_ENABLE;
206 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500207}
208
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500209static void xgbe_an73_disable_kr_training(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500210{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500211 unsigned int reg;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500212
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500213 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500214
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500215 reg &= ~XGBE_KR_TRAINING_ENABLE;
216 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg);
217}
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500218
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500219static void xgbe_kr_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500220{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500221 /* Enable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500222 xgbe_an73_enable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500223
224 /* Set MAC to 10G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500225 pdata->hw_if.set_speed(pdata, SPEED_10000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500226
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500227 /* Call PHY implementation support to complete rate change */
228 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KR);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500229}
230
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500231static void xgbe_kx_2500_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500232{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500233 /* Disable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500234 xgbe_an73_disable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500235
236 /* Set MAC to 2.5G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500237 pdata->hw_if.set_speed(pdata, SPEED_2500);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500238
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500239 /* Call PHY implementation support to complete rate change */
240 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_2500);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500241}
242
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500243static void xgbe_kx_1000_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500244{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500245 /* Disable KR training */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500246 xgbe_an73_disable_kr_training(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500247
248 /* Set MAC to 1G speed */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500249 pdata->hw_if.set_speed(pdata, SPEED_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500250
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500251 /* Call PHY implementation support to complete rate change */
252 pdata->phy_if.phy_impl.set_mode(pdata, XGBE_MODE_KX_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500253}
254
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500255static enum xgbe_mode xgbe_cur_mode(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500256{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500257 return pdata->phy_if.phy_impl.cur_mode(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500258}
259
260static bool xgbe_in_kr_mode(struct xgbe_prv_data *pdata)
261{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500262 return (xgbe_cur_mode(pdata) == XGBE_MODE_KR);
263}
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500264
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500265static void xgbe_change_mode(struct xgbe_prv_data *pdata,
266 enum xgbe_mode mode)
267{
268 switch (mode) {
269 case XGBE_MODE_KX_1000:
270 xgbe_kx_1000_mode(pdata);
271 break;
272 case XGBE_MODE_KX_2500:
273 xgbe_kx_2500_mode(pdata);
274 break;
275 case XGBE_MODE_KR:
276 xgbe_kr_mode(pdata);
277 break;
278 case XGBE_MODE_UNKNOWN:
279 break;
280 default:
281 netif_dbg(pdata, link, pdata->netdev,
282 "invalid operation mode requested (%u)\n", mode);
283 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500284}
285
286static void xgbe_switch_mode(struct xgbe_prv_data *pdata)
287{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500288 xgbe_change_mode(pdata, pdata->phy_if.phy_impl.switch_mode(pdata));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500289}
290
291static void xgbe_set_mode(struct xgbe_prv_data *pdata,
292 enum xgbe_mode mode)
293{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500294 if (mode == xgbe_cur_mode(pdata))
295 return;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500296
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500297 xgbe_change_mode(pdata, mode);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500298}
299
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500300static bool xgbe_use_mode(struct xgbe_prv_data *pdata,
301 enum xgbe_mode mode)
Lendacky, Thomas471e14b2015-05-22 16:32:14 -0500302{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500303 return pdata->phy_if.phy_impl.use_mode(pdata, mode);
Lendacky, Thomas471e14b2015-05-22 16:32:14 -0500304}
305
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500306static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
307 bool restart)
308{
309 unsigned int reg;
310
311 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1);
312 reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE;
313
314 if (enable)
315 reg |= MDIO_VEND2_CTRL1_AN_ENABLE;
316
317 if (restart)
318 reg |= MDIO_VEND2_CTRL1_AN_RESTART;
319
320 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
321}
322
323static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
324{
325 xgbe_an37_enable_interrupts(pdata);
326 xgbe_an37_set(pdata, true, true);
327
328 netif_dbg(pdata, link, pdata->netdev, "CL37 AN enabled/restarted\n");
329}
330
331static void xgbe_an37_disable(struct xgbe_prv_data *pdata)
332{
333 xgbe_an37_set(pdata, false, false);
334 xgbe_an37_disable_interrupts(pdata);
335
336 netif_dbg(pdata, link, pdata->netdev, "CL37 AN disabled\n");
337}
338
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500339static void xgbe_an73_set(struct xgbe_prv_data *pdata, bool enable,
340 bool restart)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500341{
342 unsigned int reg;
343
344 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1);
345 reg &= ~MDIO_AN_CTRL1_ENABLE;
346
347 if (enable)
348 reg |= MDIO_AN_CTRL1_ENABLE;
349
350 if (restart)
351 reg |= MDIO_AN_CTRL1_RESTART;
352
353 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg);
354}
355
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500356static void xgbe_an73_restart(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500357{
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500358 xgbe_an73_enable_interrupts(pdata);
359 xgbe_an73_set(pdata, true, true);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500360
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500361 netif_dbg(pdata, link, pdata->netdev, "CL73 AN enabled/restarted\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500362}
363
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500364static void xgbe_an73_disable(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500365{
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500366 xgbe_an73_set(pdata, false, false);
367 xgbe_an73_disable_interrupts(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500368
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500369 netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500370}
371
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500372static void xgbe_an_restart(struct xgbe_prv_data *pdata)
373{
374 switch (pdata->an_mode) {
375 case XGBE_AN_MODE_CL73:
376 xgbe_an73_restart(pdata);
377 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500378 case XGBE_AN_MODE_CL37:
379 case XGBE_AN_MODE_CL37_SGMII:
380 xgbe_an37_restart(pdata);
381 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500382 default:
383 break;
384 }
385}
386
387static void xgbe_an_disable(struct xgbe_prv_data *pdata)
388{
389 switch (pdata->an_mode) {
390 case XGBE_AN_MODE_CL73:
391 xgbe_an73_disable(pdata);
392 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500393 case XGBE_AN_MODE_CL37:
394 case XGBE_AN_MODE_CL37_SGMII:
395 xgbe_an37_disable(pdata);
396 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500397 default:
398 break;
399 }
400}
401
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500402static void xgbe_an_disable_all(struct xgbe_prv_data *pdata)
403{
404 xgbe_an73_disable(pdata);
405 xgbe_an37_disable(pdata);
406}
407
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500408static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata,
409 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500410{
411 unsigned int ad_reg, lp_reg, reg;
412
413 *state = XGBE_RX_COMPLETE;
414
415 /* If we're not in KR mode then we're done */
416 if (!xgbe_in_kr_mode(pdata))
417 return XGBE_AN_PAGE_RECEIVED;
418
419 /* Enable/Disable FEC */
420 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
421 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2);
422
423 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL);
424 reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE);
425 if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
426 reg |= pdata->fec_ability;
427
428 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg);
429
430 /* Start KR training */
431 reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL);
432 if (reg & XGBE_KR_TRAINING_ENABLE) {
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500433 if (pdata->phy_if.phy_impl.kr_training_pre)
434 pdata->phy_if.phy_impl.kr_training_pre(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500435
436 reg |= XGBE_KR_TRAINING_START;
437 XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
438 reg);
439
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500440 if (pdata->phy_if.phy_impl.kr_training_post)
441 pdata->phy_if.phy_impl.kr_training_post(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500442
443 netif_dbg(pdata, link, pdata->netdev,
444 "KR training initiated\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500445 }
446
447 return XGBE_AN_PAGE_RECEIVED;
448}
449
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500450static enum xgbe_an xgbe_an73_tx_xnp(struct xgbe_prv_data *pdata,
451 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500452{
453 u16 msg;
454
455 *state = XGBE_RX_XNP;
456
457 msg = XGBE_XNP_MCF_NULL_MESSAGE;
458 msg |= XGBE_XNP_MP_FORMATTED;
459
460 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0);
461 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
462 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_XNP, msg);
463
464 return XGBE_AN_PAGE_RECEIVED;
465}
466
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500467static enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata,
468 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500469{
470 unsigned int link_support;
471 unsigned int reg, ad_reg, lp_reg;
472
473 /* Read Base Ability register 2 first */
474 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1);
475
476 /* Check for a supported mode, otherwise restart in a different one */
477 link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20;
478 if (!(reg & link_support))
479 return XGBE_AN_INCOMPAT_LINK;
480
481 /* Check Extended Next Page support */
482 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
483 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA);
484
485 return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
486 (lp_reg & XGBE_XNP_NP_EXCHANGE))
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500487 ? xgbe_an73_tx_xnp(pdata, state)
488 : xgbe_an73_tx_training(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500489}
490
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500491static enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata,
492 enum xgbe_rx *state)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500493{
494 unsigned int ad_reg, lp_reg;
495
496 /* Check Extended Next Page support */
497 ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP);
498 lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX);
499
500 return ((ad_reg & XGBE_XNP_NP_EXCHANGE) ||
501 (lp_reg & XGBE_XNP_NP_EXCHANGE))
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500502 ? xgbe_an73_tx_xnp(pdata, state)
503 : xgbe_an73_tx_training(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500504}
505
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500506static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500507{
508 enum xgbe_rx *state;
509 unsigned long an_timeout;
510 enum xgbe_an ret;
511
512 if (!pdata->an_start) {
513 pdata->an_start = jiffies;
514 } else {
515 an_timeout = pdata->an_start +
516 msecs_to_jiffies(XGBE_AN_MS_TIMEOUT);
517 if (time_after(jiffies, an_timeout)) {
518 /* Auto-negotiation timed out, reset state */
519 pdata->kr_state = XGBE_RX_BPA;
520 pdata->kx_state = XGBE_RX_BPA;
521
522 pdata->an_start = jiffies;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500523
524 netif_dbg(pdata, link, pdata->netdev,
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500525 "CL73 AN timed out, resetting state\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500526 }
527 }
528
529 state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500530 : &pdata->kx_state;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500531
532 switch (*state) {
533 case XGBE_RX_BPA:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500534 ret = xgbe_an73_rx_bpa(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500535 break;
536
537 case XGBE_RX_XNP:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500538 ret = xgbe_an73_rx_xnp(pdata, state);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500539 break;
540
541 default:
542 ret = XGBE_AN_ERROR;
543 }
544
545 return ret;
546}
547
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500548static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500549{
550 /* Be sure we aren't looping trying to negotiate */
551 if (xgbe_in_kr_mode(pdata)) {
552 pdata->kr_state = XGBE_RX_ERROR;
553
554 if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) &&
555 !(pdata->phy.advertising & ADVERTISED_2500baseX_Full))
556 return XGBE_AN_NO_LINK;
557
558 if (pdata->kx_state != XGBE_RX_BPA)
559 return XGBE_AN_NO_LINK;
560 } else {
561 pdata->kx_state = XGBE_RX_ERROR;
562
563 if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full))
564 return XGBE_AN_NO_LINK;
565
566 if (pdata->kr_state != XGBE_RX_BPA)
567 return XGBE_AN_NO_LINK;
568 }
569
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500570 xgbe_an73_disable(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500571
572 xgbe_switch_mode(pdata);
573
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500574 xgbe_an73_restart(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500575
576 return XGBE_AN_INCOMPAT_LINK;
577}
578
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500579static void xgbe_an37_isr(struct xgbe_prv_data *pdata)
580{
581 unsigned int reg;
582
583 /* Disable AN interrupts */
584 xgbe_an37_disable_interrupts(pdata);
585
586 /* Save the interrupt(s) that fired */
587 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT);
588 pdata->an_int = reg & XGBE_AN_CL37_INT_MASK;
589 pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK;
590
591 if (pdata->an_int) {
592 /* Clear the interrupt(s) that fired and process them */
593 reg &= ~XGBE_AN_CL37_INT_MASK;
594 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg);
595
596 queue_work(pdata->an_workqueue, &pdata->an_irq_work);
597 } else {
598 /* Enable AN interrupts */
599 xgbe_an37_enable_interrupts(pdata);
600 }
601}
602
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500603static void xgbe_an73_isr(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500604{
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600605 /* Disable AN interrupts */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500606 xgbe_an73_disable_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500607
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600608 /* Save the interrupt(s) that fired */
609 pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
610
611 if (pdata->an_int) {
612 /* Clear the interrupt(s) that fired and process them */
613 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
614
615 queue_work(pdata->an_workqueue, &pdata->an_irq_work);
616 } else {
617 /* Enable AN interrupts */
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500618 xgbe_an73_enable_interrupts(pdata);
619 }
620}
621
622static irqreturn_t xgbe_an_isr(int irq, void *data)
623{
624 struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data;
625
626 netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
627
628 switch (pdata->an_mode) {
629 case XGBE_AN_MODE_CL73:
630 xgbe_an73_isr(pdata);
631 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500632 case XGBE_AN_MODE_CL37:
633 case XGBE_AN_MODE_CL37_SGMII:
634 xgbe_an37_isr(pdata);
635 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500636 default:
637 break;
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600638 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500639
640 return IRQ_HANDLED;
641}
642
643static void xgbe_an_irq_work(struct work_struct *work)
644{
645 struct xgbe_prv_data *pdata = container_of(work,
646 struct xgbe_prv_data,
647 an_irq_work);
648
649 /* Avoid a race between enabling the IRQ and exiting the work by
650 * waiting for the work to finish and then queueing it
651 */
652 flush_work(&pdata->an_work);
653 queue_work(pdata->an_workqueue, &pdata->an_work);
654}
655
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500656static const char *xgbe_state_as_string(enum xgbe_an state)
657{
658 switch (state) {
659 case XGBE_AN_READY:
660 return "Ready";
661 case XGBE_AN_PAGE_RECEIVED:
662 return "Page-Received";
663 case XGBE_AN_INCOMPAT_LINK:
664 return "Incompatible-Link";
665 case XGBE_AN_COMPLETE:
666 return "Complete";
667 case XGBE_AN_NO_LINK:
668 return "No-Link";
669 case XGBE_AN_ERROR:
670 return "Error";
671 default:
672 return "Undefined";
673 }
674}
675
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500676static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata)
677{
678 enum xgbe_an cur_state = pdata->an_state;
679
680 if (!pdata->an_int)
681 return;
682
683 if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) {
684 pdata->an_state = XGBE_AN_COMPLETE;
685 pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT;
686
687 /* If SGMII is enabled, check the link status */
688 if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) &&
689 !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS))
690 pdata->an_state = XGBE_AN_NO_LINK;
691 }
692
693 netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n",
694 xgbe_state_as_string(pdata->an_state));
695
696 cur_state = pdata->an_state;
697
698 switch (pdata->an_state) {
699 case XGBE_AN_READY:
700 break;
701
702 case XGBE_AN_COMPLETE:
703 netif_dbg(pdata, link, pdata->netdev,
704 "Auto negotiation successful\n");
705 break;
706
707 case XGBE_AN_NO_LINK:
708 break;
709
710 default:
711 pdata->an_state = XGBE_AN_ERROR;
712 }
713
714 if (pdata->an_state == XGBE_AN_ERROR) {
715 netdev_err(pdata->netdev,
716 "error during auto-negotiation, state=%u\n",
717 cur_state);
718
719 pdata->an_int = 0;
720 xgbe_an37_clear_interrupts(pdata);
721 }
722
723 if (pdata->an_state >= XGBE_AN_COMPLETE) {
724 pdata->an_result = pdata->an_state;
725 pdata->an_state = XGBE_AN_READY;
726
727 netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n",
728 xgbe_state_as_string(pdata->an_result));
729 }
730
731 xgbe_an37_enable_interrupts(pdata);
732}
733
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500734static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500735{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500736 enum xgbe_an cur_state = pdata->an_state;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500737
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600738 if (!pdata->an_int)
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500739 return;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500740
741next_int:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500742 if (pdata->an_int & XGBE_AN_CL73_PG_RCV) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500743 pdata->an_state = XGBE_AN_PAGE_RECEIVED;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500744 pdata->an_int &= ~XGBE_AN_CL73_PG_RCV;
745 } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500746 pdata->an_state = XGBE_AN_INCOMPAT_LINK;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500747 pdata->an_int &= ~XGBE_AN_CL73_INC_LINK;
748 } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500749 pdata->an_state = XGBE_AN_COMPLETE;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500750 pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500751 } else {
752 pdata->an_state = XGBE_AN_ERROR;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500753 }
754
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500755again:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500756 netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n",
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500757 xgbe_state_as_string(pdata->an_state));
758
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500759 cur_state = pdata->an_state;
760
761 switch (pdata->an_state) {
762 case XGBE_AN_READY:
763 pdata->an_supported = 0;
764 break;
765
766 case XGBE_AN_PAGE_RECEIVED:
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500767 pdata->an_state = xgbe_an73_page_received(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500768 pdata->an_supported++;
769 break;
770
771 case XGBE_AN_INCOMPAT_LINK:
772 pdata->an_supported = 0;
773 pdata->parallel_detect = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500774 pdata->an_state = xgbe_an73_incompat_link(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500775 break;
776
777 case XGBE_AN_COMPLETE:
778 pdata->parallel_detect = pdata->an_supported ? 0 : 1;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500779 netif_dbg(pdata, link, pdata->netdev, "%s successful\n",
780 pdata->an_supported ? "Auto negotiation"
781 : "Parallel detection");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500782 break;
783
784 case XGBE_AN_NO_LINK:
785 break;
786
787 default:
788 pdata->an_state = XGBE_AN_ERROR;
789 }
790
791 if (pdata->an_state == XGBE_AN_NO_LINK) {
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600792 pdata->an_int = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500793 xgbe_an73_clear_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500794 } else if (pdata->an_state == XGBE_AN_ERROR) {
795 netdev_err(pdata->netdev,
796 "error during auto-negotiation, state=%u\n",
797 cur_state);
798
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600799 pdata->an_int = 0;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500800 xgbe_an73_clear_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500801 }
802
803 if (pdata->an_state >= XGBE_AN_COMPLETE) {
804 pdata->an_result = pdata->an_state;
805 pdata->an_state = XGBE_AN_READY;
806 pdata->kr_state = XGBE_RX_BPA;
807 pdata->kx_state = XGBE_RX_BPA;
808 pdata->an_start = 0;
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500809
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500810 netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n",
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500811 xgbe_state_as_string(pdata->an_result));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500812 }
813
814 if (cur_state != pdata->an_state)
815 goto again;
816
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600817 if (pdata->an_int)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500818 goto next_int;
819
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500820 xgbe_an73_enable_interrupts(pdata);
821}
822
823static void xgbe_an_state_machine(struct work_struct *work)
824{
825 struct xgbe_prv_data *pdata = container_of(work,
826 struct xgbe_prv_data,
827 an_work);
828
829 mutex_lock(&pdata->an_mutex);
830
831 switch (pdata->an_mode) {
832 case XGBE_AN_MODE_CL73:
833 xgbe_an73_state_machine(pdata);
834 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500835 case XGBE_AN_MODE_CL37:
836 case XGBE_AN_MODE_CL37_SGMII:
837 xgbe_an37_state_machine(pdata);
838 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500839 default:
840 break;
841 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500842
843 mutex_unlock(&pdata->an_mutex);
844}
845
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500846static void xgbe_an37_init(struct xgbe_prv_data *pdata)
847{
848 unsigned int reg;
849
850 /* Set up Advertisement register */
851 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE);
852 if (pdata->phy.advertising & ADVERTISED_Pause)
853 reg |= 0x100;
854 else
855 reg &= ~0x100;
856
857 if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
858 reg |= 0x80;
859 else
860 reg &= ~0x80;
861
862 /* Full duplex, but not half */
863 reg |= XGBE_AN_CL37_FD_MASK;
864 reg &= ~XGBE_AN_CL37_HD_MASK;
865
866 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg);
867
868 /* Set up the Control register */
869 reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL);
870 reg &= XGBE_AN_CL37_TX_CONFIG_MASK;
871 reg &= XGBE_AN_CL37_PCS_MODE_MASK;
872
873 switch (pdata->an_mode) {
874 case XGBE_AN_MODE_CL37:
875 reg |= XGBE_AN_CL37_PCS_MODE_BASEX;
876 break;
877 case XGBE_AN_MODE_CL37_SGMII:
878 reg |= XGBE_AN_CL37_PCS_MODE_SGMII;
879 break;
880 default:
881 break;
882 }
883
884 XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg);
885
886 netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n",
887 (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII");
888}
889
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500890static void xgbe_an73_init(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500891{
892 unsigned int reg;
893
894 /* Set up Advertisement register 3 first */
895 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
896 if (pdata->phy.advertising & ADVERTISED_10000baseR_FEC)
897 reg |= 0xc000;
898 else
899 reg &= ~0xc000;
900
901 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg);
902
903 /* Set up Advertisement register 2 next */
904 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
905 if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
906 reg |= 0x80;
907 else
908 reg &= ~0x80;
909
910 if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) ||
911 (pdata->phy.advertising & ADVERTISED_2500baseX_Full))
912 reg |= 0x20;
913 else
914 reg &= ~0x20;
915
916 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg);
917
918 /* Set up Advertisement register 1 last */
919 reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
920 if (pdata->phy.advertising & ADVERTISED_Pause)
921 reg |= 0x400;
922 else
923 reg &= ~0x400;
924
925 if (pdata->phy.advertising & ADVERTISED_Asym_Pause)
926 reg |= 0x800;
927 else
928 reg &= ~0x800;
929
930 /* We don't intend to perform XNP */
931 reg &= ~XGBE_XNP_NP_EXCHANGE;
932
933 XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -0500934
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500935 netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n");
936}
937
938static void xgbe_an_init(struct xgbe_prv_data *pdata)
939{
940 /* Set up advertisement registers based on current settings */
941 pdata->an_mode = pdata->phy_if.phy_impl.an_mode(pdata);
942 switch (pdata->an_mode) {
943 case XGBE_AN_MODE_CL73:
944 xgbe_an73_init(pdata);
945 break;
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -0500946 case XGBE_AN_MODE_CL37:
947 case XGBE_AN_MODE_CL37_SGMII:
948 xgbe_an37_init(pdata);
949 break;
Lendacky, Thomasa64def42016-11-03 13:18:38 -0500950 default:
951 break;
952 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500953}
954
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -0500955static const char *xgbe_phy_fc_string(struct xgbe_prv_data *pdata)
956{
957 if (pdata->tx_pause && pdata->rx_pause)
958 return "rx/tx";
959 else if (pdata->rx_pause)
960 return "rx";
961 else if (pdata->tx_pause)
962 return "tx";
963 else
964 return "off";
965}
966
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500967static const char *xgbe_phy_speed_string(int speed)
968{
969 switch (speed) {
970 case SPEED_1000:
971 return "1Gbps";
972 case SPEED_2500:
973 return "2.5Gbps";
974 case SPEED_10000:
975 return "10Gbps";
976 case SPEED_UNKNOWN:
977 return "Unknown";
978 default:
979 return "Unsupported";
980 }
981}
982
983static void xgbe_phy_print_status(struct xgbe_prv_data *pdata)
984{
985 if (pdata->phy.link)
986 netdev_info(pdata->netdev,
987 "Link is Up - %s/%s - flow control %s\n",
988 xgbe_phy_speed_string(pdata->phy.speed),
989 pdata->phy.duplex == DUPLEX_FULL ? "Full" : "Half",
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -0500990 xgbe_phy_fc_string(pdata));
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500991 else
992 netdev_info(pdata->netdev, "Link is Down\n");
993}
994
995static void xgbe_phy_adjust_link(struct xgbe_prv_data *pdata)
996{
997 int new_state = 0;
998
999 if (pdata->phy.link) {
1000 /* Flow control support */
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001001 pdata->pause_autoneg = pdata->phy.pause_autoneg;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001002
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001003 if (pdata->tx_pause != pdata->phy.tx_pause) {
1004 new_state = 1;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001005 pdata->hw_if.config_tx_flow_control(pdata);
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001006 pdata->tx_pause = pdata->phy.tx_pause;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001007 }
1008
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001009 if (pdata->rx_pause != pdata->phy.rx_pause) {
1010 new_state = 1;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001011 pdata->hw_if.config_rx_flow_control(pdata);
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001012 pdata->rx_pause = pdata->phy.rx_pause;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001013 }
1014
1015 /* Speed support */
1016 if (pdata->phy_speed != pdata->phy.speed) {
1017 new_state = 1;
1018 pdata->phy_speed = pdata->phy.speed;
1019 }
1020
1021 if (pdata->phy_link != pdata->phy.link) {
1022 new_state = 1;
1023 pdata->phy_link = pdata->phy.link;
1024 }
1025 } else if (pdata->phy_link) {
1026 new_state = 1;
1027 pdata->phy_link = 0;
1028 pdata->phy_speed = SPEED_UNKNOWN;
1029 }
1030
1031 if (new_state && netif_msg_link(pdata))
1032 xgbe_phy_print_status(pdata);
1033}
1034
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001035static bool xgbe_phy_valid_speed(struct xgbe_prv_data *pdata, int speed)
1036{
1037 return pdata->phy_if.phy_impl.valid_speed(pdata, speed);
1038}
1039
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001040static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata)
1041{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001042 enum xgbe_mode mode;
1043
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001044 netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n");
1045
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001046 /* Disable auto-negotiation */
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001047 xgbe_an_disable(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001048
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001049 /* Set specified mode for specified speed */
1050 mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed);
1051 switch (mode) {
1052 case XGBE_MODE_KX_1000:
1053 case XGBE_MODE_KX_2500:
1054 case XGBE_MODE_KR:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001055 break;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001056 case XGBE_MODE_UNKNOWN:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001057 default:
1058 return -EINVAL;
1059 }
1060
1061 /* Validate duplex mode */
1062 if (pdata->phy.duplex != DUPLEX_FULL)
1063 return -EINVAL;
1064
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001065 xgbe_set_mode(pdata, mode);
1066
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001067 return 0;
1068}
1069
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001070static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1071{
1072 set_bit(XGBE_LINK_INIT, &pdata->dev_state);
1073 pdata->link_check = jiffies;
1074
1075 if (pdata->phy.autoneg != AUTONEG_ENABLE)
1076 return xgbe_phy_config_fixed(pdata);
1077
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001078 netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n");
1079
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001080 /* Disable auto-negotiation interrupt */
1081 disable_irq(pdata->an_irq);
1082
1083 /* Start auto-negotiation in a supported mode */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001084 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001085 xgbe_set_mode(pdata, XGBE_MODE_KR);
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001086 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1087 xgbe_set_mode(pdata, XGBE_MODE_KX_2500);
1088 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1089 xgbe_set_mode(pdata, XGBE_MODE_KX_1000);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001090 } else {
1091 enable_irq(pdata->an_irq);
1092 return -EINVAL;
1093 }
1094
1095 /* Disable and stop any in progress auto-negotiation */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001096 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001097
1098 /* Clear any auto-negotitation interrupts */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001099 xgbe_an_clear_interrupts_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001100
1101 pdata->an_result = XGBE_AN_READY;
1102 pdata->an_state = XGBE_AN_READY;
1103 pdata->kr_state = XGBE_RX_BPA;
1104 pdata->kx_state = XGBE_RX_BPA;
1105
1106 /* Re-enable auto-negotiation interrupt */
1107 enable_irq(pdata->an_irq);
1108
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001109 xgbe_an_init(pdata);
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001110 xgbe_an_restart(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001111
1112 return 0;
1113}
1114
1115static int xgbe_phy_config_aneg(struct xgbe_prv_data *pdata)
1116{
1117 int ret;
1118
1119 mutex_lock(&pdata->an_mutex);
1120
1121 ret = __xgbe_phy_config_aneg(pdata);
1122 if (ret)
1123 set_bit(XGBE_LINK_ERR, &pdata->dev_state);
1124 else
1125 clear_bit(XGBE_LINK_ERR, &pdata->dev_state);
1126
1127 mutex_unlock(&pdata->an_mutex);
1128
1129 return ret;
1130}
1131
1132static bool xgbe_phy_aneg_done(struct xgbe_prv_data *pdata)
1133{
1134 return (pdata->an_result == XGBE_AN_COMPLETE);
1135}
1136
1137static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata)
1138{
1139 unsigned long link_timeout;
1140
1141 link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001142 if (time_after(jiffies, link_timeout)) {
1143 netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001144 xgbe_phy_config_aneg(pdata);
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001145 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001146}
1147
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001148static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001149{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001150 return pdata->phy_if.phy_impl.an_outcome(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001151}
1152
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001153static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001154{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001155 enum xgbe_mode mode;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001156
1157 pdata->phy.lp_advertising = 0;
1158
1159 if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect)
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001160 mode = xgbe_cur_mode(pdata);
1161 else
1162 mode = xgbe_phy_status_aneg(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001163
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001164 switch (mode) {
1165 case XGBE_MODE_KX_1000:
1166 pdata->phy.speed = SPEED_1000;
1167 break;
1168 case XGBE_MODE_KX_2500:
1169 pdata->phy.speed = SPEED_2500;
1170 break;
1171 case XGBE_MODE_KR:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001172 pdata->phy.speed = SPEED_10000;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001173 break;
1174 case XGBE_MODE_UNKNOWN:
1175 default:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001176 pdata->phy.speed = SPEED_UNKNOWN;
1177 }
1178
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001179 pdata->phy.duplex = DUPLEX_FULL;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001180
1181 xgbe_set_mode(pdata, mode);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001182}
1183
1184static void xgbe_phy_status(struct xgbe_prv_data *pdata)
1185{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001186 unsigned int link_aneg;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001187
1188 if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) {
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001189 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001190
1191 pdata->phy.link = 0;
1192 goto adjust_link;
1193 }
1194
1195 link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE);
1196
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001197 pdata->phy.link = pdata->phy_if.phy_impl.link_status(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001198 if (pdata->phy.link) {
1199 if (link_aneg && !xgbe_phy_aneg_done(pdata)) {
1200 xgbe_check_link_timeout(pdata);
1201 return;
1202 }
1203
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001204 xgbe_phy_status_result(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001205
1206 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
1207 clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
1208
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001209 netif_carrier_on(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001210 } else {
1211 if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) {
1212 xgbe_check_link_timeout(pdata);
1213
1214 if (link_aneg)
1215 return;
1216 }
1217
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001218 xgbe_phy_status_result(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001219
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001220 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001221 }
1222
1223adjust_link:
1224 xgbe_phy_adjust_link(pdata);
1225}
1226
1227static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
1228{
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001229 netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n");
1230
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001231 if (!pdata->phy_started)
1232 return;
1233
1234 /* Indicate the PHY is down */
1235 pdata->phy_started = 0;
1236
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001237 /* Disable auto-negotiation */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001238 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001239
1240 devm_free_irq(pdata->dev, pdata->an_irq, pdata);
1241
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001242 pdata->phy_if.phy_impl.stop(pdata);
1243
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001244 pdata->phy.link = 0;
Lendacky, Thomas50789845c2015-09-30 08:53:22 -05001245 netif_carrier_off(pdata->netdev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001246
1247 xgbe_phy_adjust_link(pdata);
1248}
1249
1250static int xgbe_phy_start(struct xgbe_prv_data *pdata)
1251{
1252 struct net_device *netdev = pdata->netdev;
1253 int ret;
1254
Lendacky, Thomasd5c78392015-05-22 16:32:21 -05001255 netif_dbg(pdata, link, pdata->netdev, "starting PHY\n");
1256
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001257 ret = pdata->phy_if.phy_impl.start(pdata);
1258 if (ret)
1259 return ret;
1260
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001261 ret = devm_request_irq(pdata->dev, pdata->an_irq,
1262 xgbe_an_isr, 0, pdata->an_name,
1263 pdata);
1264 if (ret) {
1265 netdev_err(netdev, "phy irq request failed\n");
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001266 goto err_stop;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001267 }
1268
1269 /* Set initial mode - call the mode setting routines
1270 * directly to insure we are properly configured
1271 */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001272 if (xgbe_use_mode(pdata, XGBE_MODE_KR)) {
1273 xgbe_kr_mode(pdata);
1274 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) {
1275 xgbe_kx_2500_mode(pdata);
1276 } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) {
1277 xgbe_kx_1000_mode(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001278 } else {
1279 ret = -EINVAL;
1280 goto err_irq;
1281 }
1282
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001283 /* Indicate the PHY is up and running */
1284 pdata->phy_started = 1;
1285
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001286 xgbe_an_init(pdata);
Lendacky, Thomasa64def42016-11-03 13:18:38 -05001287 xgbe_an_enable_interrupts(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001288
1289 return xgbe_phy_config_aneg(pdata);
1290
1291err_irq:
1292 devm_free_irq(pdata->dev, pdata->an_irq, pdata);
1293
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001294err_stop:
1295 pdata->phy_if.phy_impl.stop(pdata);
1296
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001297 return ret;
1298}
1299
1300static int xgbe_phy_reset(struct xgbe_prv_data *pdata)
1301{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001302 int ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001303
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001304 ret = pdata->phy_if.phy_impl.reset(pdata);
1305 if (ret)
1306 return ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001307
1308 /* Disable auto-negotiation for now */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001309 xgbe_an_disable_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001310
1311 /* Clear auto-negotiation interrupts */
Lendacky, Thomas1bf40ad2016-11-03 13:18:47 -05001312 xgbe_an_clear_interrupts_all(pdata);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001313
1314 return 0;
1315}
1316
1317static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001318{
1319 struct device *dev = pdata->dev;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001320
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001321 dev_dbg(dev, "\n************* PHY Reg dump **********************\n");
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001322
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001323 dev_dbg(dev, "PCS Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001324 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001325 dev_dbg(dev, "PCS Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001326 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001327 dev_dbg(dev, "Phy Id (PHYS ID 1 %#06x)= %#06x\n", MDIO_DEVID1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001328 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001329 dev_dbg(dev, "Phy Id (PHYS ID 2 %#06x)= %#06x\n", MDIO_DEVID2,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001330 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001331 dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001332 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001333 dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS2,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001334 XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2));
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001335
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001336 dev_dbg(dev, "Auto-Neg Control Reg (%#06x) = %#06x\n", MDIO_CTRL1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001337 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001338 dev_dbg(dev, "Auto-Neg Status Reg (%#06x) = %#06x\n", MDIO_STAT1,
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001339 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001340 dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001341 MDIO_AN_ADVERTISE,
1342 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001343 dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001344 MDIO_AN_ADVERTISE + 1,
1345 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001346 dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001347 MDIO_AN_ADVERTISE + 2,
1348 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2));
Lendacky, Thomasd9682c92016-11-03 13:17:38 -05001349 dev_dbg(dev, "Auto-Neg Completion Reg (%#06x) = %#06x\n",
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001350 MDIO_AN_COMP_STAT,
1351 XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT));
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001352
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001353 dev_dbg(dev, "\n*************************************************\n");
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001354}
1355
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001356static int xgbe_phy_best_advertised_speed(struct xgbe_prv_data *pdata)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001357{
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001358 if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full)
1359 return SPEED_10000;
1360 else if (pdata->phy.advertising & ADVERTISED_2500baseX_Full)
1361 return SPEED_2500;
1362 else if (pdata->phy.advertising & ADVERTISED_1000baseKX_Full)
1363 return SPEED_1000;
1364
1365 return SPEED_UNKNOWN;
1366}
1367
1368static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
1369{
1370 xgbe_phy_stop(pdata);
1371
1372 pdata->phy_if.phy_impl.exit(pdata);
1373}
1374
1375static int xgbe_phy_init(struct xgbe_prv_data *pdata)
1376{
1377 int ret;
1378
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001379 mutex_init(&pdata->an_mutex);
1380 INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work);
1381 INIT_WORK(&pdata->an_work, xgbe_an_state_machine);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001382 pdata->mdio_mmd = MDIO_MMD_PCS;
1383
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001384 /* Check for FEC support */
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001385 pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD,
1386 MDIO_PMA_10GBR_FECABLE);
1387 pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE |
1388 MDIO_PMA_10GBR_FECABLE_ERRABLE);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001389
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001390 /* Setup the phy (including supported features) */
1391 ret = pdata->phy_if.phy_impl.init(pdata);
1392 if (ret)
1393 return ret;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001394 pdata->phy.advertising = pdata->phy.supported;
1395
1396 pdata->phy.address = 0;
1397
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001398 if (pdata->phy.advertising & ADVERTISED_Autoneg) {
1399 pdata->phy.autoneg = AUTONEG_ENABLE;
1400 pdata->phy.speed = SPEED_UNKNOWN;
1401 pdata->phy.duplex = DUPLEX_UNKNOWN;
1402 } else {
1403 pdata->phy.autoneg = AUTONEG_DISABLE;
1404 pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata);
1405 pdata->phy.duplex = DUPLEX_FULL;
1406 }
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001407
1408 pdata->phy.link = 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001409
Lendacky, Thomasc1ce2f72015-05-14 11:44:27 -05001410 pdata->phy.pause_autoneg = pdata->pause_autoneg;
1411 pdata->phy.tx_pause = pdata->tx_pause;
1412 pdata->phy.rx_pause = pdata->rx_pause;
1413
1414 /* Fix up Flow Control advertising */
1415 pdata->phy.advertising &= ~ADVERTISED_Pause;
1416 pdata->phy.advertising &= ~ADVERTISED_Asym_Pause;
1417
1418 if (pdata->rx_pause) {
1419 pdata->phy.advertising |= ADVERTISED_Pause;
1420 pdata->phy.advertising |= ADVERTISED_Asym_Pause;
1421 }
1422
1423 if (pdata->tx_pause)
1424 pdata->phy.advertising ^= ADVERTISED_Asym_Pause;
1425
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -05001426 if (netif_msg_drv(pdata))
1427 xgbe_dump_phy_registers(pdata);
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001428
1429 return 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001430}
1431
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001432void xgbe_init_function_ptrs_phy(struct xgbe_phy_if *phy_if)
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001433{
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001434 phy_if->phy_init = xgbe_phy_init;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001435 phy_if->phy_exit = xgbe_phy_exit;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001436
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001437 phy_if->phy_reset = xgbe_phy_reset;
1438 phy_if->phy_start = xgbe_phy_start;
1439 phy_if->phy_stop = xgbe_phy_stop;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001440
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -05001441 phy_if->phy_status = xgbe_phy_status;
1442 phy_if->phy_config_aneg = xgbe_phy_config_aneg;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -05001443
1444 phy_if->phy_valid_speed = xgbe_phy_valid_speed;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001445}