]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/dsa/mv88e6xxx/serdes.c
Linux 5.6-rc7
[linux.git] / drivers / net / dsa / mv88e6xxx / serdes.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
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>
8  */
9
10 #include <linux/interrupt.h>
11 #include <linux/irqdomain.h>
12 #include <linux/mii.h>
13
14 #include "chip.h"
15 #include "global2.h"
16 #include "phy.h"
17 #include "port.h"
18 #include "serdes.h"
19
20 static 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
28 static 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
36 static 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
44 static 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
52 int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
53                            bool up)
54 {
55         u16 val, new_val;
56         int err;
57
58         err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
59         if (err)
60                 return err;
61
62         if (up)
63                 new_val = val & ~BMCR_PDOWN;
64         else
65                 new_val = val | BMCR_PDOWN;
66
67         if (val != new_val)
68                 err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
69
70         return err;
71 }
72
73 u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
74 {
75         u8 cmode = chip->ports[port].cmode;
76         u8 lane = 0;
77
78         if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
79             (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
80             (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
81                 lane = 0xff; /* Unused */
82
83         return lane;
84 }
85
86 static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
87 {
88         if (mv88e6xxx_serdes_get_lane(chip, port))
89                 return true;
90
91         return false;
92 }
93
94 struct mv88e6352_serdes_hw_stat {
95         char string[ETH_GSTRING_LEN];
96         int sizeof_stat;
97         int reg;
98 };
99
100 static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
101         { "serdes_fibre_rx_error", 16, 21 },
102         { "serdes_PRBS_error", 32, 24 },
103 };
104
105 int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
106 {
107         if (mv88e6352_port_has_serdes(chip, port))
108                 return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
109
110         return 0;
111 }
112
113 int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
114                                  int port, uint8_t *data)
115 {
116         struct mv88e6352_serdes_hw_stat *stat;
117         int i;
118
119         if (!mv88e6352_port_has_serdes(chip, port))
120                 return 0;
121
122         for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
123                 stat = &mv88e6352_serdes_hw_stats[i];
124                 memcpy(data + i * ETH_GSTRING_LEN, stat->string,
125                        ETH_GSTRING_LEN);
126         }
127         return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
128 }
129
130 static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
131                                           struct mv88e6352_serdes_hw_stat *stat)
132 {
133         u64 val = 0;
134         u16 reg;
135         int err;
136
137         err = mv88e6352_serdes_read(chip, stat->reg, &reg);
138         if (err) {
139                 dev_err(chip->dev, "failed to read statistic\n");
140                 return 0;
141         }
142
143         val = reg;
144
145         if (stat->sizeof_stat == 32) {
146                 err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
147                 if (err) {
148                         dev_err(chip->dev, "failed to read statistic\n");
149                         return 0;
150                 }
151                 val = val << 16 | reg;
152         }
153
154         return val;
155 }
156
157 int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
158                                uint64_t *data)
159 {
160         struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
161         struct mv88e6352_serdes_hw_stat *stat;
162         u64 value;
163         int i;
164
165         if (!mv88e6352_port_has_serdes(chip, port))
166                 return 0;
167
168         BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
169                      ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
170
171         for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
172                 stat = &mv88e6352_serdes_hw_stats[i];
173                 value = mv88e6352_serdes_get_stat(chip, stat);
174                 mv88e6xxx_port->serdes_stats[i] += value;
175                 data[i] = mv88e6xxx_port->serdes_stats[i];
176         }
177
178         return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
179 }
180
181 static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
182 {
183         struct dsa_switch *ds = chip->ds;
184         u16 status;
185         bool up;
186         int err;
187
188         err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
189         if (err)
190                 return;
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         err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
197         if (err)
198                 return;
199
200         up = status & BMSR_LSTATUS;
201
202         dsa_port_phylink_mac_change(ds, port, up);
203 }
204
205 irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
206                                         u8 lane)
207 {
208         irqreturn_t ret = IRQ_NONE;
209         u16 status;
210         int err;
211
212         err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
213         if (err)
214                 return ret;
215
216         if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
217                 ret = IRQ_HANDLED;
218                 mv88e6352_serdes_irq_link(chip, port);
219         }
220
221         return ret;
222 }
223
224 int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
225                                 bool enable)
226 {
227         u16 val = 0;
228
229         if (enable)
230                 val |= MV88E6352_SERDES_INT_LINK_CHANGE;
231
232         return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
233 }
234
235 unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
236 {
237         return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
238 }
239
240 u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
241 {
242         u8 cmode = chip->ports[port].cmode;
243         u8 lane = 0;
244
245         switch (port) {
246         case 5:
247                 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
248                     cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
249                     cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
250                         lane = MV88E6341_PORT5_LANE;
251                 break;
252         }
253
254         return lane;
255 }
256
257 u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
258 {
259         u8 cmode = chip->ports[port].cmode;
260         u8 lane = 0;
261
262         switch (port) {
263         case 9:
264                 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
265                     cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
266                     cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
267                         lane = MV88E6390_PORT9_LANE0;
268                 break;
269         case 10:
270                 if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
271                     cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
272                     cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
273                         lane = MV88E6390_PORT10_LANE0;
274                 break;
275         }
276
277         return lane;
278 }
279
280 u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
281 {
282         u8 cmode_port = chip->ports[port].cmode;
283         u8 cmode_port10 = chip->ports[10].cmode;
284         u8 cmode_port9 = chip->ports[9].cmode;
285         u8 lane = 0;
286
287         switch (port) {
288         case 2:
289                 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
290                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
291                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
292                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
293                                 lane = MV88E6390_PORT9_LANE1;
294                 break;
295         case 3:
296                 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
297                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
298                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
299                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
300                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
301                                 lane = MV88E6390_PORT9_LANE2;
302                 break;
303         case 4:
304                 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
305                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
306                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
307                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
308                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
309                                 lane = MV88E6390_PORT9_LANE3;
310                 break;
311         case 5:
312                 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
313                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
314                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
315                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
316                                 lane = MV88E6390_PORT10_LANE1;
317                 break;
318         case 6:
319                 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
320                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
321                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
322                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
323                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
324                                 lane = MV88E6390_PORT10_LANE2;
325                 break;
326         case 7:
327                 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
328                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
329                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
330                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
331                         if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
332                                 lane = MV88E6390_PORT10_LANE3;
333                 break;
334         case 9:
335                 if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
336                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
337                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
338                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
339                     cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
340                         lane = MV88E6390_PORT9_LANE0;
341                 break;
342         case 10:
343                 if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
344                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
345                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
346                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
347                     cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
348                         lane = MV88E6390_PORT10_LANE0;
349                 break;
350         }
351
352         return lane;
353 }
354
355 /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
356 static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
357                                       bool up)
358 {
359         u16 val, new_val;
360         int err;
361
362         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
363                                     MV88E6390_PCS_CONTROL_1, &val);
364
365         if (err)
366                 return err;
367
368         if (up)
369                 new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
370                                   MV88E6390_PCS_CONTROL_1_LOOPBACK |
371                                   MV88E6390_PCS_CONTROL_1_PDOWN);
372         else
373                 new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;
374
375         if (val != new_val)
376                 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
377                                              MV88E6390_PCS_CONTROL_1, new_val);
378
379         return err;
380 }
381
382 /* Set power up/down for SGMII and 1000Base-X */
383 static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
384                                         bool up)
385 {
386         u16 val, new_val;
387         int err;
388
389         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
390                                     MV88E6390_SGMII_CONTROL, &val);
391         if (err)
392                 return err;
393
394         if (up)
395                 new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
396                                   MV88E6390_SGMII_CONTROL_LOOPBACK |
397                                   MV88E6390_SGMII_CONTROL_PDOWN);
398         else
399                 new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;
400
401         if (val != new_val)
402                 err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
403                                              MV88E6390_SGMII_CONTROL, new_val);
404
405         return err;
406 }
407
408 struct mv88e6390_serdes_hw_stat {
409         char string[ETH_GSTRING_LEN];
410         int reg;
411 };
412
413 static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = {
414         { "serdes_rx_pkts", 0xf021 },
415         { "serdes_rx_bytes", 0xf024 },
416         { "serdes_rx_pkts_error", 0xf027 },
417 };
418
419 int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
420 {
421         if (mv88e6390_serdes_get_lane(chip, port) == 0)
422                 return 0;
423
424         return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
425 }
426
427 int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
428                                  int port, uint8_t *data)
429 {
430         struct mv88e6390_serdes_hw_stat *stat;
431         int i;
432
433         if (mv88e6390_serdes_get_lane(chip, port) == 0)
434                 return 0;
435
436         for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
437                 stat = &mv88e6390_serdes_hw_stats[i];
438                 memcpy(data + i * ETH_GSTRING_LEN, stat->string,
439                        ETH_GSTRING_LEN);
440         }
441         return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
442 }
443
444 static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane,
445                                           struct mv88e6390_serdes_hw_stat *stat)
446 {
447         u16 reg[3];
448         int err, i;
449
450         for (i = 0; i < 3; i++) {
451                 err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
452                                             stat->reg + i, &reg[i]);
453                 if (err) {
454                         dev_err(chip->dev, "failed to read statistic\n");
455                         return 0;
456                 }
457         }
458
459         return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32);
460 }
461
462 int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
463                                uint64_t *data)
464 {
465         struct mv88e6390_serdes_hw_stat *stat;
466         int lane;
467         int i;
468
469         lane = mv88e6390_serdes_get_lane(chip, port);
470         if (lane == 0)
471                 return 0;
472
473         for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) {
474                 stat = &mv88e6390_serdes_hw_stats[i];
475                 data[i] = mv88e6390_serdes_get_stat(chip, lane, stat);
476         }
477
478         return ARRAY_SIZE(mv88e6390_serdes_hw_stats);
479 }
480
481 static int mv88e6390_serdes_enable_checker(struct mv88e6xxx_chip *chip, u8 lane)
482 {
483         u16 reg;
484         int err;
485
486         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
487                                     MV88E6390_PG_CONTROL, &reg);
488         if (err)
489                 return err;
490
491         reg |= MV88E6390_PG_CONTROL_ENABLE_PC;
492         return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
493                                       MV88E6390_PG_CONTROL, reg);
494 }
495
496 int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
497                            bool up)
498 {
499         u8 cmode = chip->ports[port].cmode;
500         int err = 0;
501
502         switch (cmode) {
503         case MV88E6XXX_PORT_STS_CMODE_SGMII:
504         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
505         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
506                 err = mv88e6390_serdes_power_sgmii(chip, lane, up);
507                 break;
508         case MV88E6XXX_PORT_STS_CMODE_XAUI:
509         case MV88E6XXX_PORT_STS_CMODE_RXAUI:
510                 err = mv88e6390_serdes_power_10g(chip, lane, up);
511                 break;
512         }
513
514         if (!err && up)
515                 err = mv88e6390_serdes_enable_checker(chip, lane);
516
517         return err;
518 }
519
520 static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
521                                             int port, u8 lane)
522 {
523         u8 cmode = chip->ports[port].cmode;
524         struct dsa_switch *ds = chip->ds;
525         int duplex = DUPLEX_UNKNOWN;
526         int speed = SPEED_UNKNOWN;
527         phy_interface_t mode;
528         int link, err;
529         u16 status;
530
531         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
532                                     MV88E6390_SGMII_PHY_STATUS, &status);
533         if (err) {
534                 dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
535                 return;
536         }
537
538         link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
539                LINK_FORCED_UP : LINK_FORCED_DOWN;
540
541         if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
542                 duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
543                          DUPLEX_FULL : DUPLEX_HALF;
544
545                 switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
546                 case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
547                         if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
548                                 speed = SPEED_2500;
549                         else
550                                 speed = SPEED_1000;
551                         break;
552                 case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
553                         speed = SPEED_100;
554                         break;
555                 case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
556                         speed = SPEED_10;
557                         break;
558                 default:
559                         dev_err(chip->dev, "invalid PHY speed\n");
560                         return;
561                 }
562         }
563
564         switch (cmode) {
565         case MV88E6XXX_PORT_STS_CMODE_SGMII:
566                 mode = PHY_INTERFACE_MODE_SGMII;
567                 break;
568         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
569                 mode = PHY_INTERFACE_MODE_1000BASEX;
570                 break;
571         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
572                 mode = PHY_INTERFACE_MODE_2500BASEX;
573                 break;
574         default:
575                 mode = PHY_INTERFACE_MODE_NA;
576         }
577
578         err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
579                                        PAUSE_OFF, mode);
580         if (err)
581                 dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
582                         err);
583         else
584                 dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
585 }
586
587 static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
588                                              u8 lane, bool enable)
589 {
590         u16 val = 0;
591
592         if (enable)
593                 val |= MV88E6390_SGMII_INT_LINK_DOWN |
594                         MV88E6390_SGMII_INT_LINK_UP;
595
596         return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
597                                       MV88E6390_SGMII_INT_ENABLE, val);
598 }
599
600 int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
601                                 bool enable)
602 {
603         u8 cmode = chip->ports[port].cmode;
604
605         switch (cmode) {
606         case MV88E6XXX_PORT_STS_CMODE_SGMII:
607         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
608         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
609                 return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
610         }
611
612         return 0;
613 }
614
615 static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
616                                              u8 lane, u16 *status)
617 {
618         int err;
619
620         err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
621                                     MV88E6390_SGMII_INT_STATUS, status);
622
623         return err;
624 }
625
626 irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port,
627                                         u8 lane)
628 {
629         u8 cmode = chip->ports[port].cmode;
630         irqreturn_t ret = IRQ_NONE;
631         u16 status;
632         int err;
633
634         switch (cmode) {
635         case MV88E6XXX_PORT_STS_CMODE_SGMII:
636         case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
637         case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
638                 err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
639                 if (err)
640                         return ret;
641                 if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
642                               MV88E6390_SGMII_INT_LINK_UP)) {
643                         ret = IRQ_HANDLED;
644                         mv88e6390_serdes_irq_link_sgmii(chip, port, lane);
645                 }
646         }
647
648         return ret;
649 }
650
651 unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
652 {
653         return irq_find_mapping(chip->g2_irq.domain, port);
654 }