serdes.c 16.8 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9
/*
 * Marvell 88E6xxx SERDES manipulation, via SMI bus
 *
 * Copyright (c) 2008 Marvell Semiconductor
 *
 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
 */

10 11
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
12 13
#include <linux/mii.h>

14
#include "chip.h"
15
#include "global2.h"
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include "phy.h"
#include "port.h"
#include "serdes.h"

static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
				 u16 *val)
{
	return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
				       MV88E6352_SERDES_PAGE_FIBER,
				       reg, val);
}

static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
				  u16 val)
{
	return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
					MV88E6352_SERDES_PAGE_FIBER,
					reg, val);
}

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
static int mv88e6390_serdes_read(struct mv88e6xxx_chip *chip,
				 int lane, int device, int reg, u16 *val)
{
	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;

	return mv88e6xxx_phy_read(chip, lane, reg_c45, val);
}

static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
				  int lane, int device, int reg, u16 val)
{
	int reg_c45 = MII_ADDR_C45 | device << 16 | reg;

	return mv88e6xxx_phy_write(chip, lane, reg_c45, val);
}

52 53
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
			   bool up)
54 55 56 57 58 59 60 61
{
	u16 val, new_val;
	int err;

	err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
	if (err)
		return err;

62
	if (up)
63 64 65 66 67 68 69 70 71 72
		new_val = val & ~BMCR_PDOWN;
	else
		new_val = val | BMCR_PDOWN;

	if (val != new_val)
		err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);

	return err;
}

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 79
	if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
	    (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
80
	    (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
81 82 83 84 85 86 87 88
		lane = 0xff; /* Unused */

	return lane;
}

static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
{
	if (mv88e6xxx_serdes_get_lane(chip, port))
89
		return true;
90

91
	return false;
92 93
}

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
struct mv88e6352_serdes_hw_stat {
	char string[ETH_GSTRING_LEN];
	int sizeof_stat;
	int reg;
};

static struct mv88e6352_serdes_hw_stat mv88e6352_serdes_hw_stats[] = {
	{ "serdes_fibre_rx_error", 16, 21 },
	{ "serdes_PRBS_error", 32, 24 },
};

int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port)
{
	if (mv88e6352_port_has_serdes(chip, port))
		return ARRAY_SIZE(mv88e6352_serdes_hw_stats);

	return 0;
}

113 114
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
				 int port, uint8_t *data)
115 116 117 118 119
{
	struct mv88e6352_serdes_hw_stat *stat;
	int i;

	if (!mv88e6352_port_has_serdes(chip, port))
120
		return 0;
121 122 123 124 125 126

	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
		stat = &mv88e6352_serdes_hw_stats[i];
		memcpy(data + i * ETH_GSTRING_LEN, stat->string,
		       ETH_GSTRING_LEN);
	}
127
	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
}

static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
					  struct mv88e6352_serdes_hw_stat *stat)
{
	u64 val = 0;
	u16 reg;
	int err;

	err = mv88e6352_serdes_read(chip, stat->reg, &reg);
	if (err) {
		dev_err(chip->dev, "failed to read statistic\n");
		return 0;
	}

	val = reg;

	if (stat->sizeof_stat == 32) {
		err = mv88e6352_serdes_read(chip, stat->reg + 1, &reg);
		if (err) {
			dev_err(chip->dev, "failed to read statistic\n");
			return 0;
		}
		val = val << 16 | reg;
	}

	return val;
}

157 158
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
			       uint64_t *data)
159 160 161 162 163 164 165
{
	struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
	struct mv88e6352_serdes_hw_stat *stat;
	u64 value;
	int i;

	if (!mv88e6352_port_has_serdes(chip, port))
166
		return 0;
167 168 169 170 171 172 173 174 175 176

	BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
		     ARRAY_SIZE(mv88e6xxx_port->serdes_stats));

	for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) {
		stat = &mv88e6352_serdes_hw_stats[i];
		value = mv88e6352_serdes_get_stat(chip, stat);
		mv88e6xxx_port->serdes_stats[i] += value;
		data[i] = mv88e6xxx_port->serdes_stats[i];
	}
177 178

	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
179 180
}

181 182 183 184 185
static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
{
	struct dsa_switch *ds = chip->ds;
	u16 status;
	bool up;
186
	int err;
187

188 189 190
	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
	if (err)
		return;
191 192 193 194 195

	/* Status must be read twice in order to give the current link
	 * status. Otherwise the change in link status since the last
	 * read of the register is returned.
	 */
196 197 198
	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
	if (err)
		return;
199 200 201 202 203 204 205 206 207 208 209 210 211 212

	up = status & BMSR_LSTATUS;

	dsa_port_phylink_mac_change(ds, port, up);
}

static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_port *port = dev_id;
	struct mv88e6xxx_chip *chip = port->chip;
	irqreturn_t ret = IRQ_NONE;
	u16 status;
	int err;

213
	mv88e6xxx_reg_lock(chip);
214 215 216 217 218 219 220 221 222 223

	err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
	if (err)
		goto out;

	if (status & MV88E6352_SERDES_INT_LINK_CHANGE) {
		ret = IRQ_HANDLED;
		mv88e6352_serdes_irq_link(chip, port->port);
	}
out:
224
	mv88e6xxx_reg_unlock(chip);
225 226 227 228

	return ret;
}

229 230
int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
				bool enable)
231
{
232
	u16 val = 0;
233

234 235 236 237
	if (enable)
		val |= MV88E6352_SERDES_INT_LINK_CHANGE;

	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, val);
238 239
}

240 241 242 243 244
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
	return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
}

245 246
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
{
247
	unsigned int irq;
248
	u8 lane;
249 250
	int err;

251 252
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
253 254
		return 0;

255 256
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
257
		return 0;
258

259 260
	chip->ports[port].serdes_irq = irq;

261 262 263
	/* Requesting the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
264
	mv88e6xxx_reg_unlock(chip);
265 266 267 268
	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
				   mv88e6352_serdes_thread_fn,
				   IRQF_ONESHOT, "mv88e6xxx-serdes",
				   &chip->ports[port]);
269
	mv88e6xxx_reg_lock(chip);
270 271 272 273 274 275 276

	if (err) {
		dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
			err);
		return err;
	}

277
	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
278 279 280 281
}

void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{
282 283 284 285
	u8 lane;

	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
286 287
		return;

288
	mv88e6xxx_serdes_irq_disable(chip, port, lane);
289 290 291 292

	/* Freeing the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
293
	mv88e6xxx_reg_unlock(chip);
294
	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
295
	mv88e6xxx_reg_lock(chip);
296 297 298 299

	chip->ports[port].serdes_irq = 0;
}

300
u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
301 302
{
	u8 cmode = chip->ports[port].cmode;
303
	u8 lane = 0;
304

305 306 307 308 309 310 311
	switch (port) {
	case 5:
		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			lane = MV88E6341_PORT5_LANE;
		break;
312 313
	}

314
	return lane;
315 316
}

317
u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
318
{
319
	u8 cmode = chip->ports[port].cmode;
320
	u8 lane = 0;
321 322 323

	switch (port) {
	case 9:
324
		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
325
		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
326 327
		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			lane = MV88E6390_PORT9_LANE0;
328
		break;
329
	case 10:
330
		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
331
		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
332 333
		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			lane = MV88E6390_PORT10_LANE0;
334
		break;
335
	}
336

337
	return lane;
338 339
}

340
u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
341
{
342 343 344 345
	u8 cmode_port = chip->ports[port].cmode;
	u8 cmode_port10 = chip->ports[10].cmode;
	u8 cmode_port9 = chip->ports[9].cmode;
	u8 lane = 0;
346 347 348

	switch (port) {
	case 2:
349
		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
350
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
351 352 353
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT9_LANE1;
354
		break;
355
	case 3:
356
		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
357 358
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
359 360 361
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT9_LANE2;
362
		break;
363
	case 4:
364
		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
365 366
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
367 368 369
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT9_LANE3;
370
		break;
371
	case 5:
372
		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
373
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
374 375 376
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT10_LANE1;
377
		break;
378
	case 6:
379
		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
380 381
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
382 383 384
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT10_LANE2;
385
		break;
386
	case 7:
387
		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
388 389
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
390 391 392
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX)
				lane = MV88E6390_PORT10_LANE3;
393
		break;
394
	case 9:
395
		if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
396 397 398
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
399 400
		    cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			lane = MV88E6390_PORT9_LANE0;
401
		break;
402
	case 10:
403
		if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
404 405 406
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
407 408
		    cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
			lane = MV88E6390_PORT10_LANE0;
409
		break;
410
	}
411

412
	return lane;
413 414
}

415
/* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */
416
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
417
				      bool up)
418 419 420 421
{
	u16 val, new_val;
	int err;

422 423 424
	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_PCS_CONTROL_1, &val);

425 426 427
	if (err)
		return err;

428
	if (up)
429 430 431 432 433 434 435
		new_val = val & ~(MV88E6390_PCS_CONTROL_1_RESET |
				  MV88E6390_PCS_CONTROL_1_LOOPBACK |
				  MV88E6390_PCS_CONTROL_1_PDOWN);
	else
		new_val = val | MV88E6390_PCS_CONTROL_1_PDOWN;

	if (val != new_val)
436 437
		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
					     MV88E6390_PCS_CONTROL_1, new_val);
438 439 440 441

	return err;
}

442
/* Set power up/down for SGMII and 1000Base-X */
443
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
444
					bool up)
445 446 447 448
{
	u16 val, new_val;
	int err;

449 450
	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_SGMII_CONTROL, &val);
451 452 453
	if (err)
		return err;

454
	if (up)
455 456 457 458 459 460 461
		new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET |
				  MV88E6390_SGMII_CONTROL_LOOPBACK |
				  MV88E6390_SGMII_CONTROL_PDOWN);
	else
		new_val = val | MV88E6390_SGMII_CONTROL_PDOWN;

	if (val != new_val)
462 463
		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
					     MV88E6390_SGMII_CONTROL, new_val);
464 465 466 467

	return err;
}

468 469
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane,
			   bool up)
470
{
471
	u8 cmode = chip->ports[port].cmode;
472

473 474
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
475
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
476
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
477
		return mv88e6390_serdes_power_sgmii(chip, lane, up);
478 479
	case MV88E6XXX_PORT_STS_CMODE_XAUI:
	case MV88E6XXX_PORT_STS_CMODE_RXAUI:
480
		return mv88e6390_serdes_power_10g(chip, lane, up);
481 482 483 484
	}

	return 0;
}
485

486
static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
487
					    int port, u8 lane)
488
{
489
	u8 cmode = chip->ports[port].cmode;
490
	struct dsa_switch *ds = chip->ds;
491 492
	int duplex = DUPLEX_UNKNOWN;
	int speed = SPEED_UNKNOWN;
493
	phy_interface_t mode;
494
	int link, err;
495 496
	u16 status;

497 498 499 500 501 502
	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_SGMII_PHY_STATUS, &status);
	if (err) {
		dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err);
		return;
	}
503

504 505 506 507 508 509 510 511 512
	link = status & MV88E6390_SGMII_PHY_STATUS_LINK ?
	       LINK_FORCED_UP : LINK_FORCED_DOWN;

	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
		duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
			 DUPLEX_FULL : DUPLEX_HALF;

		switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
		case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
513 514 515 516
			if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
				speed = SPEED_2500;
			else
				speed = SPEED_1000;
517 518 519 520 521 522 523 524 525 526 527 528
			break;
		case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
			speed = SPEED_100;
			break;
		case MV88E6390_SGMII_PHY_STATUS_SPEED_10:
			speed = SPEED_10;
			break;
		default:
			dev_err(chip->dev, "invalid PHY speed\n");
			return;
		}
	}
529

530 531 532 533
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
		mode = PHY_INTERFACE_MODE_SGMII;
		break;
534
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
535 536 537 538 539 540 541 542 543
		mode = PHY_INTERFACE_MODE_1000BASEX;
		break;
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		mode = PHY_INTERFACE_MODE_2500BASEX;
		break;
	default:
		mode = PHY_INTERFACE_MODE_NA;
	}

544
	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
545
				       PAUSE_OFF, mode);
546 547 548 549 550
	if (err)
		dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
			err);
	else
		dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP);
551 552 553
}

static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
554
					     u8 lane, bool enable)
555
{
556
	u16 val = 0;
557

558 559 560
	if (enable)
		val |= MV88E6390_SGMII_INT_LINK_DOWN |
			MV88E6390_SGMII_INT_LINK_UP;
561

562 563
	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
				      MV88E6390_SGMII_INT_ENABLE, val);
564 565
}

566 567
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane,
				bool enable)
568 569 570 571 572
{
	u8 cmode = chip->ports[port].cmode;

	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
573
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
574
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
575
		return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable);
576 577
	}

578
	return 0;
579 580 581
}

static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
582
					     u8 lane, u16 *status)
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
{
	int err;

	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_SGMII_INT_STATUS, status);

	return err;
}

static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
{
	struct mv88e6xxx_port *port = dev_id;
	struct mv88e6xxx_chip *chip = port->chip;
	irqreturn_t ret = IRQ_NONE;
	u8 cmode = port->cmode;
	u16 status;
	int err;
600
	u8 lane;
601

602
	mv88e6xxx_reg_lock(chip);
603

604 605
	lane = mv88e6xxx_serdes_get_lane(chip, port->port);
	if (!lane)
606 607
		goto out;

608 609
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
610
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
611 612 613 614
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
		if (err)
			goto out;
615 616
		if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
			      MV88E6390_SGMII_INT_LINK_UP)) {
617 618 619 620 621
			ret = IRQ_HANDLED;
			mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
		}
	}
out:
622
	mv88e6xxx_reg_unlock(chip);
623 624 625 626

	return ret;
}

627 628 629 630 631
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
	return irq_find_mapping(chip->g2_irq.domain, port);
}

632
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
633
{
634
	unsigned int irq;
635
	int err;
636
	u8 lane;
637

638 639 640
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
		return 0;
641

642 643
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
644
		return 0;
645

646 647
	chip->ports[port].serdes_irq = irq;

648 649 650
	/* Requesting the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
651
	mv88e6xxx_reg_unlock(chip);
652 653 654 655
	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
				   mv88e6390_serdes_thread_fn,
				   IRQF_ONESHOT, "mv88e6xxx-serdes",
				   &chip->ports[port]);
656
	mv88e6xxx_reg_lock(chip);
657 658 659 660 661 662 663

	if (err) {
		dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
			err);
		return err;
	}

664
	return mv88e6xxx_serdes_irq_enable(chip, port, lane);
665 666
}

667
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
668
{
669
	u8 lane;
670

671 672
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
673 674
		return;

675
	mv88e6xxx_serdes_irq_disable(chip, port, lane);
676 677 678 679

	/* Freeing the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
680
	mv88e6xxx_reg_unlock(chip);
681
	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
682
	mv88e6xxx_reg_lock(chip);
683 684

	chip->ports[port].serdes_irq = 0;
685
}