]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/dsa/mv88e6xxx/serdes.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / net / dsa / mv88e6xxx / serdes.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
6d91782f
AL
2/*
3 * Marvell 88E6xxx SERDES manipulation, via SMI bus
4 *
5 * Copyright (c) 2008 Marvell Semiconductor
6 *
7 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
6d91782f
AL
8 */
9
efd1ba6a
AL
10#include <linux/interrupt.h>
11#include <linux/irqdomain.h>
6d91782f
AL
12#include <linux/mii.h>
13
4d5f2ba7 14#include "chip.h"
6335e9f2 15#include "global2.h"
6d91782f
AL
16#include "phy.h"
17#include "port.h"
18#include "serdes.h"
19
20static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
21 u16 *val)
22{
23 return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
24 MV88E6352_SERDES_PAGE_FIBER,
25 reg, val);
26}
27
28static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
29 u16 val)
30{
31 return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
32 MV88E6352_SERDES_PAGE_FIBER,
33 reg, val);
34}
35
e6891c76
AL
36static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
37 int lane, int device, int reg, u16 *val)
38{
39 int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
40
41 return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
42}
43
44static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
45 int lane, int device, int reg, u16 val)
46{
47 int reg_c45 = MII_ADDR_C45 | device << 16 | reg;
48
49 return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
50}
51
6d91782f
AL
52static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
53{
54 u16 val, new_val;
55 int err;
56
57 err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
58 if (err)
59 return err;
60
61 if (on)
62 new_val = val & ~BMCR_PDOWN;
63 else
64 new_val = val | BMCR_PDOWN;
65
66 if (val != new_val)
67 err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
68
69 return err;
70}
71
eb755c3f 72static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
6d91782f 73{
2d2e1dd2 74 u8 cmode = chip->ports[port].cmode;
6d91782f 75
5f83dc93
VD
76 if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) ||
77 (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) ||
eb755c3f 78 (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
b1312b85 79 return true;
eb755c3f 80
b1312b85 81 return false;
eb755c3f
AL
82}
83
84int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
85{
86 int err;
87
88 if (mv88e6352_port_has_serdes(chip, port)) {
6d91782f
AL
89 err = mv88e6352_serdes_power_set(chip, on);
90 if (err < 0)
91 return err;
92 }
93
94 return 0;
95}
6335e9f2 96
cda9f4aa
AL
97struct mv88e6352_serdes_hw_stat {
98 char string[ETH_GSTRING_LEN];
99 int sizeof_stat;
100 int reg;
101};
102
103static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
104 { "serdes_fibre_rx_error", 16, 21 },
105 { "serdes_PRBS_error", 32, 24 },
106};
107
108int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
109{
110 if (mv88e6352_port_has_serdes(chip, port))
111 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
112
113 return 0;
114}
115
65f60e45
AL
116int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
117 int port, uint8_t *data)
cda9f4aa
AL
118{
119 struct mv88e6352_serdes_hw_stat *stat;
120 int i;
121
122 if (!mv88e6352_port_has_serdes(chip, port))
65f60e45 123 return 0;
cda9f4aa
AL
124
125 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
126 stat = &mv88e6352_serdes_hw_stats[i];
127 memcpy(data + i * ETH_GSTRING_LEN, stat->string,
128 ETH_GSTRING_LEN);
129 }
65f60e45 130 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
cda9f4aa
AL
131}
132
133static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
134 struct mv88e6352_serdes_hw_stat *stat)
135{
136 u64 val = 0;
137 u16 reg;
138 int err;
139
140 err = mv88e6352_serdes_read(chip, stat->reg, &reg);
141 if (err) {
142 dev_err(chip->dev, "failed to read statistic\n");
143 return 0;
144 }
145
146 val = reg;
147
148 if (stat->sizeof_stat == 32) {
149 err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
150 if (err) {
151 dev_err(chip->dev, "failed to read statistic\n");
152 return 0;
153 }
154 val = val << 16 | reg;
155 }
156
157 return val;
158}
159
65f60e45
AL
160int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
161 uint64_t *data)
cda9f4aa
AL
162{
163 struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
164 struct mv88e6352_serdes_hw_stat *stat;
165 u64 value;
166 int i;
167
168 if (!mv88e6352_port_has_serdes(chip, port))
65f60e45 169 return 0;
cda9f4aa
AL
170
171 BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
172 ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
173
174 for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
175 stat = &mv88e6352_serdes_hw_stats[i];
176 value = mv88e6352_serdes_get_stat(chip, stat);
177 mv88e6xxx_port->serdes_stats[i] += value;
178 data[i] = mv88e6xxx_port->serdes_stats[i];
179 }
65f60e45
AL
180
181 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
cda9f4aa
AL
182}
183
4382172f
AL
184static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
185{
186 struct dsa_switch *ds = chip->ds;
187 u16 status;
188 bool up;
189
190 mv88e6352_serdes_read(chip, MII_BMSR, &status);
191
192 /* Status must be read twice in order to give the current link
193 * status. Otherwise the change in link status since the last
194 * read of the register is returned.
195 */
196 mv88e6352_serdes_read(chip, MII_BMSR, &status);
197
198 up = status & BMSR_LSTATUS;
199
200 dsa_port_phylink_mac_change(ds, port, up);
201}
202
203static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
204{
205 struct mv88e6xxx_port *port = dev_id;
206 struct mv88e6xxx_chip *chip = port->chip;
207 irqreturn_t ret = IRQ_NONE;
208 u16 status;
209 int err;
210
211 mutex_lock(&chip->reg_lock);
212
213 err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
214 if (err)
215 goto out;
216
217 if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
218 ret = IRQ_HANDLED;
219 mv88e6352_serdes_irq_link(chip, port->port);
220 }
221out:
222 mutex_unlock(&chip->reg_lock);
223
224 return ret;
225}
226
227static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip)
228{
229 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE,
230 MV88E6352_SERDES_INT_LINK_CHANGE);
231}
232
233static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip)
234{
235 return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0);
236}
237
238int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
239{
240 int err;
241
242 if (!mv88e6352_port_has_serdes(chip, port))
243 return 0;
244
245 chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
246 MV88E6352_SERDES_IRQ);
247 if (chip->ports[port].serdes_irq < 0) {
248 dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
249 chip->ports[port].serdes_irq);
250 return chip->ports[port].serdes_irq;
251 }
252
253 /* Requesting the IRQ will trigger irq callbacks. So we cannot
254 * hold the reg_lock.
255 */
256 mutex_unlock(&chip->reg_lock);
257 err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
258 mv88e6352_serdes_thread_fn,
259 IRQF_ONESHOT, "mv88e6xxx-serdes",
260 &chip->ports[port]);
261 mutex_lock(&chip->reg_lock);
262
263 if (err) {
264 dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
265 err);
266 return err;
267 }
268
269 return mv88e6352_serdes_irq_enable(chip);
270}
271
272void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
273{
274 if (!mv88e6352_port_has_serdes(chip, port))
275 return;
276
277 mv88e6352_serdes_irq_disable(chip);
278
279 /* Freeing the IRQ will trigger irq callbacks. So we cannot
280 * hold the reg_lock.
281 */
282 mutex_unlock(&chip->reg_lock);
283 free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
284 mutex_lock(&chip->reg_lock);
285
286 chip->ports[port].serdes_irq = 0;
287}
288
07ffbd74
AL
289/* Return the SERDES lane address a port is using. Only Ports 9 and 10
290 * have SERDES lanes. Returns -ENODEV if a port does not have a lane.
291 */
292static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
293{
2d2e1dd2 294 u8 cmode = chip->ports[port].cmode;
07ffbd74
AL
295
296 switch (port) {
297 case 9:
298 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
299 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
300 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
301 return MV88E6390_PORT9_LANE0;
302 return -ENODEV;
303 case 10:
304 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
305 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
306 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
307 return MV88E6390_PORT10_LANE0;
308 return -ENODEV;
309 default:
310 return -ENODEV;
311 }
312}
313
a8c01c0d
AL
314/* Return the SERDES lane address a port is using. Ports 9 and 10 can
315 * use multiple lanes. If so, return the first lane the port uses.
316 * Returns -ENODEV if a port does not have a lane.
317 */
734447d4 318int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
a8c01c0d
AL
319{
320 u8 cmode_port9, cmode_port10, cmode_port;
a8c01c0d 321
2d2e1dd2
AL
322 cmode_port9 = chip->ports[9].cmode;
323 cmode_port10 = chip->ports[10].cmode;
324 cmode_port = chip->ports[port].cmode;
a8c01c0d
AL
325
326 switch (port) {
327 case 2:
328 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
329 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
330 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
331 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
332 return MV88E6390_PORT9_LANE1;
333 return -ENODEV;
334 case 3:
335 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
336 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
337 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
338 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
339 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
340 return MV88E6390_PORT9_LANE2;
341 return -ENODEV;
342 case 4:
343 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
344 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
345 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
346 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
347 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
348 return MV88E6390_PORT9_LANE3;
349 return -ENODEV;
350 case 5:
351 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
352 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
353 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
354 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
355 return MV88E6390_PORT10_LANE1;
356 return -ENODEV;
357 case 6:
358 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
359 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
360 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
361 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
362 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
363 return MV88E6390_PORT10_LANE2;
364 return -ENODEV;
365 case 7:
366 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
367 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
368 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
369 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
370 if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
371 return MV88E6390_PORT10_LANE3;
372 return -ENODEV;
373 case 9:
374 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
375 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
376 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
377 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
378 cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
379 return MV88E6390_PORT9_LANE0;
380 return -ENODEV;
381 case 10:
382 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
383 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
384 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
385 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
386 cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
387 return MV88E6390_PORT10_LANE0;
388 return -ENODEV;
389 default:
390 return -ENODEV;
391 }
392}
393
6335e9f2 394/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
23ef57d8
AL
395static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
396 bool on)
6335e9f2
AL
397{
398 u16 val, new_val;
6335e9f2
AL
399 int err;
400
e6891c76
AL
401 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
402 MV88E6390_PCS_CONTROL_1, &val);
403
6335e9f2
AL
404 if (err)
405 return err;
406
407 if (on)
408 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
409 MV88E6390_PCS_CONTROL_1_LOOPBACK |
410 MV88E6390_PCS_CONTROL_1_PDOWN);
411 else
412 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
413
414 if (val != new_val)
e6891c76
AL
415 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
416 MV88E6390_PCS_CONTROL_1, new_val);
6335e9f2
AL
417
418 return err;
419}
420
a8c01c0d 421/* Set the power on/off for SGMII and 1000Base-X */
23ef57d8
AL
422static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
423 bool on)
6335e9f2
AL
424{
425 u16 val, new_val;
6335e9f2
AL
426 int err;
427
e6891c76
AL
428 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
429 MV88E6390_SGMII_CONTROL, &val);
6335e9f2
AL
430 if (err)
431 return err;
432
433 if (on)
434 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
435 MV88E6390_SGMII_CONTROL_LOOPBACK |
436 MV88E6390_SGMII_CONTROL_PDOWN);
437 else
438 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
439
440 if (val != new_val)
e6891c76
AL
441 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
442 MV88E6390_SGMII_CONTROL, new_val);
6335e9f2
AL
443
444 return err;
445}
446
a8c01c0d
AL
447static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
448 int lane, bool on)
6335e9f2 449{
2d2e1dd2 450 u8 cmode = chip->ports[port].cmode;
6335e9f2 451
6335e9f2 452 switch (cmode) {
5f83dc93 453 case MV88E6XXX_PORT_STS_CMODE_SGMII:
a8c01c0d 454 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
f8236a08 455 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
23ef57d8 456 return mv88e6390_serdes_power_sgmii(chip, lane, on);
5f83dc93
VD
457 case MV88E6XXX_PORT_STS_CMODE_XAUI:
458 case MV88E6XXX_PORT_STS_CMODE_RXAUI:
23ef57d8 459 return mv88e6390_serdes_power_10g(chip, lane, on);
6335e9f2
AL
460 }
461
462 return 0;
463}
464
465int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
466{
a8c01c0d 467 int lane;
6335e9f2 468
a8c01c0d
AL
469 lane = mv88e6390_serdes_get_lane(chip, port);
470 if (lane == -ENODEV)
471 return 0;
472
473 if (lane < 0)
474 return lane;
6335e9f2 475
07ffbd74
AL
476 switch (port) {
477 case 9 ... 10:
478 return mv88e6390_serdes_power_lane(chip, port, lane, on);
479 }
480
481 return 0;
482}
483
484int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
485{
486 int lane;
487
488 lane = mv88e6390x_serdes_get_lane(chip, port);
489 if (lane == -ENODEV)
490 return 0;
491
492 if (lane < 0)
493 return lane;
494
6335e9f2 495 switch (port) {
a8c01c0d
AL
496 case 2 ... 4:
497 case 5 ... 7:
498 case 9 ... 10:
499 return mv88e6390_serdes_power_lane(chip, port, lane, on);
6335e9f2
AL
500 }
501
502 return 0;
503}
5bafeb6e 504
efd1ba6a
AL
505static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
506 int port, int lane)
507{
508 struct dsa_switch *ds = chip->ds;
72d8b4fd
HK
509 int duplex = DUPLEX_UNKNOWN;
510 int speed = SPEED_UNKNOWN;
511 int link, err;
efd1ba6a 512 u16 status;
efd1ba6a 513
72d8b4fd
HK
514 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
515 MV88E6390_SGMII_PHY_STATUS, &status);
516 if (err) {
517 dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
518 return;
519 }
efd1ba6a 520
72d8b4fd
HK
521 link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
522 LINK_FORCED_UP : LINK_FORCED_DOWN;
523
524 if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
525 duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
526 DUPLEX_FULL : DUPLEX_HALF;
527
528 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
529 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
530 speed = SPEED_1000;
531 break;
532 case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
533 speed = SPEED_100;
534 break;
535 case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
536 speed = SPEED_10;
537 break;
538 default:
539 dev_err(chip->dev, "invalid PHY speed\n");
540 return;
541 }
542 }
efd1ba6a 543
72d8b4fd
HK
544 err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
545 PAUSE_OFF, PHY_INTERFACE_MODE_NA);
546 if (err)
547 dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
548 err);
549 else
550 dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
efd1ba6a
AL
551}
552
553static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
554 int lane)
555{
556 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
557 MV88E6390_SGMII_INT_ENABLE,
558 MV88E6390_SGMII_INT_LINK_DOWN |
559 MV88E6390_SGMII_INT_LINK_UP);
560}
561
562static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
563 int lane)
564{
565 return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
566 MV88E6390_SGMII_INT_ENABLE, 0);
567}
568
569int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
570 int lane)
571{
572 u8 cmode = chip->ports[port].cmode;
573 int err = 0;
574
575 switch (cmode) {
576 case MV88E6XXX_PORT_STS_CMODE_SGMII:
577 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
578 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
579 err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
580 }
581
582 return err;
583}
584
585int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
586 int lane)
587{
588 u8 cmode = chip->ports[port].cmode;
589 int err = 0;
590
591 switch (cmode) {
592 case MV88E6XXX_PORT_STS_CMODE_SGMII:
593 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
594 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
595 err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
596 }
597
598 return err;
599}
600
601static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
602 int lane, u16 *status)
603{
604 int err;
605
606 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
607 MV88E6390_SGMII_INT_STATUS, status);
608
609 return err;
610}
611
612static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
613{
614 struct mv88e6xxx_port *port = dev_id;
615 struct mv88e6xxx_chip *chip = port->chip;
616 irqreturn_t ret = IRQ_NONE;
617 u8 cmode = port->cmode;
618 u16 status;
619 int lane;
620 int err;
621
622 lane = mv88e6390x_serdes_get_lane(chip, port->port);
623
624 mutex_lock(&chip->reg_lock);
625
626 switch (cmode) {
627 case MV88E6XXX_PORT_STS_CMODE_SGMII:
628 case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
629 case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
630 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
631 if (err)
632 goto out;
6feddb49
DC
633 if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
634 MV88E6390_SGMII_INT_LINK_UP)) {
efd1ba6a
AL
635 ret = IRQ_HANDLED;
636 mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
637 }
638 }
639out:
640 mutex_unlock(&chip->reg_lock);
641
642 return ret;
643}
644
2defda1f 645int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
efd1ba6a
AL
646{
647 int lane;
648 int err;
649
efd1ba6a
AL
650 lane = mv88e6390x_serdes_get_lane(chip, port);
651
652 if (lane == -ENODEV)
653 return 0;
654
655 if (lane < 0)
656 return lane;
657
658 chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
659 port);
660 if (chip->ports[port].serdes_irq < 0) {
661 dev_err(chip->dev, "Unable to map SERDES irq: %d\n",
662 chip->ports[port].serdes_irq);
663 return chip->ports[port].serdes_irq;
664 }
665
666 /* Requesting the IRQ will trigger irq callbacks. So we cannot
667 * hold the reg_lock.
668 */
669 mutex_unlock(&chip->reg_lock);
670 err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
671 mv88e6390_serdes_thread_fn,
672 IRQF_ONESHOT, "mv88e6xxx-serdes",
673 &chip->ports[port]);
674 mutex_lock(&chip->reg_lock);
675
676 if (err) {
677 dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
678 err);
679 return err;
680 }
681
682 return mv88e6390_serdes_irq_enable(chip, port, lane);
683}
684
2defda1f
AL
685int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
686{
687 if (port < 9)
688 return 0;
689
6fb6e637 690 return mv88e6390x_serdes_irq_setup(chip, port);
2defda1f
AL
691}
692
693void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
efd1ba6a
AL
694{
695 int lane = mv88e6390x_serdes_get_lane(chip, port);
696
2defda1f 697 if (lane == -ENODEV)
efd1ba6a
AL
698 return;
699
700 if (lane < 0)
701 return;
702
703 mv88e6390_serdes_irq_disable(chip, port, lane);
704
705 /* Freeing the IRQ will trigger irq callbacks. So we cannot
706 * hold the reg_lock.
707 */
708 mutex_unlock(&chip->reg_lock);
709 free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
710 mutex_lock(&chip->reg_lock);
734447d4
AL
711
712 chip->ports[port].serdes_irq = 0;
efd1ba6a
AL
713}
714
2defda1f
AL
715void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
716{
717 if (port < 9)
718 return;
719
720 mv88e6390x_serdes_irq_free(chip, port);
721}
722
5bafeb6e
MB
723int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
724{
2d2e1dd2 725 u8 cmode = chip->ports[port].cmode;
5bafeb6e
MB
726
727 if (port != 5)
728 return 0;
729
5bafeb6e
MB
730 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
731 cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
732 cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
23ef57d8
AL
733 return mv88e6390_serdes_power_sgmii(chip, MV88E6341_ADDR_SERDES,
734 on);
5bafeb6e
MB
735
736 return 0;
737}