serdes.c 17.6 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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
{
	u16 val, new_val;
	int err;

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

	if (on)
		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;
}

72
u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
73
{
74
	u8 cmode = chip->ports[port].cmode;
75
	u8 lane = 0;
76

77 78
	if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
	    (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
79
	    (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
80 81 82 83 84 85 86 87
		lane = 0xff; /* Unused */

	return lane;
}

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

90
	return false;
91 92 93 94 95 96 97
}

int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
	int err;

	if (mv88e6352_port_has_serdes(chip, port)) {
98 99 100 101 102 103 104
		err = mv88e6352_serdes_power_set(chip, on);
		if (err < 0)
			return err;
	}

	return 0;
}
105

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
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;
}

125 126
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
				 int port, uint8_t *data)
127 128 129 130 131
{
	struct mv88e6352_serdes_hw_stat *stat;
	int i;

	if (!mv88e6352_port_has_serdes(chip, port))
132
		return 0;
133 134 135 136 137 138

	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);
	}
139
	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
}

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;
}

169 170
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
			       uint64_t *data)
171 172 173 174 175 176 177
{
	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))
178
		return 0;
179 180 181 182 183 184 185 186 187 188

	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];
	}
189 190

	return ARRAY_SIZE(mv88e6352_serdes_hw_stats);
191 192
}

193 194 195 196 197
static void mv88e6352_serdes_irq_link(struct mv88e6xxx_chip *chip, int port)
{
	struct dsa_switch *ds = chip->ds;
	u16 status;
	bool up;
198
	int err;
199

200 201 202
	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
	if (err)
		return;
203 204 205 206 207

	/* 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.
	 */
208 209 210
	err = mv88e6352_serdes_read(chip, MII_BMSR, &status);
	if (err)
		return;
211 212 213 214 215 216 217 218 219 220 221 222 223 224

	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;

225
	mv88e6xxx_reg_lock(chip);
226 227 228 229 230 231 232 233 234 235

	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:
236
	mv88e6xxx_reg_unlock(chip);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251

	return ret;
}

static int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip)
{
	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE,
				      MV88E6352_SERDES_INT_LINK_CHANGE);
}

static int mv88e6352_serdes_irq_disable(struct mv88e6xxx_chip *chip)
{
	return mv88e6352_serdes_write(chip, MV88E6352_SERDES_INT_ENABLE, 0);
}

252 253 254 255 256
unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
	return irq_find_mapping(chip->g2_irq.domain, MV88E6352_SERDES_IRQ);
}

257 258
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
{
259
	unsigned int irq;
260 261 262 263 264
	int err;

	if (!mv88e6352_port_has_serdes(chip, port))
		return 0;

265 266
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
267
		return 0;
268

269 270
	chip->ports[port].serdes_irq = irq;

271 272 273
	/* Requesting the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
274
	mv88e6xxx_reg_unlock(chip);
275 276 277 278
	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
				   mv88e6352_serdes_thread_fn,
				   IRQF_ONESHOT, "mv88e6xxx-serdes",
				   &chip->ports[port]);
279
	mv88e6xxx_reg_lock(chip);
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

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

	return mv88e6352_serdes_irq_enable(chip);
}

void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{
	if (!mv88e6352_port_has_serdes(chip, port))
		return;

	mv88e6352_serdes_irq_disable(chip);

	/* Freeing the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
300
	mv88e6xxx_reg_unlock(chip);
301
	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
302
	mv88e6xxx_reg_lock(chip);
303 304 305 306

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

307
u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
308 309
{
	u8 cmode = chip->ports[port].cmode;
310
	u8 lane = 0;
311

312 313 314 315 316 317 318
	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;
319 320
	}

321
	return lane;
322 323
}

324
u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
325
{
326
	u8 cmode = chip->ports[port].cmode;
327
	u8 lane = 0;
328 329 330

	switch (port) {
	case 9:
331
		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
332
		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
333 334
		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			lane = MV88E6390_PORT9_LANE0;
335
		break;
336
	case 10:
337
		if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
338
		    cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
339 340
		    cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
			lane = MV88E6390_PORT10_LANE0;
341
		break;
342
	}
343

344
	return lane;
345 346
}

347
u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
348
{
349 350 351 352
	u8 cmode_port = chip->ports[port].cmode;
	u8 cmode_port10 = chip->ports[10].cmode;
	u8 cmode_port9 = chip->ports[9].cmode;
	u8 lane = 0;
353 354 355

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

419
	return lane;
420 421
}

422
/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
423
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
424
				      bool on)
425 426 427 428
{
	u16 val, new_val;
	int err;

429 430 431
	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_PCS_CONTROL_1, &val);

432 433 434 435 436 437 438 439 440 441 442
	if (err)
		return err;

	if (on)
		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)
443 444
		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
					     MV88E6390_PCS_CONTROL_1, new_val);
445 446 447 448

	return err;
}

449
/* Set the power on/off for SGMII and 1000Base-X */
450
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
451
					bool on)
452 453 454 455
{
	u16 val, new_val;
	int err;

456 457
	err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
				    MV88E6390_SGMII_CONTROL, &val);
458 459 460 461 462 463 464 465 466 467 468
	if (err)
		return err;

	if (on)
		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)
469 470
		err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
					     MV88E6390_SGMII_CONTROL, new_val);
471 472 473 474 475 476

	return err;
}

int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
477
	u8 cmode = chip->ports[port].cmode;
478
	u8 lane;
479

480 481 482
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
		return 0;
483

484 485
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
486
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
487 488 489 490 491
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		return mv88e6390_serdes_power_sgmii(chip, lane, on);
	case MV88E6XXX_PORT_STS_CMODE_XAUI:
	case MV88E6XXX_PORT_STS_CMODE_RXAUI:
		return mv88e6390_serdes_power_10g(chip, lane, on);
492 493 494 495
	}

	return 0;
}
496

497
static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
498
					    int port, u8 lane)
499
{
500
	u8 cmode = chip->ports[port].cmode;
501
	struct dsa_switch *ds = chip->ds;
502 503
	int duplex = DUPLEX_UNKNOWN;
	int speed = SPEED_UNKNOWN;
504
	phy_interface_t mode;
505
	int link, err;
506 507
	u16 status;

508 509 510 511 512 513
	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;
	}
514

515 516 517 518 519 520 521 522 523
	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:
524 525 526 527
			if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
				speed = SPEED_2500;
			else
				speed = SPEED_1000;
528 529 530 531 532 533 534 535 536 537 538 539
			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;
		}
	}
540

541 542 543 544
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
		mode = PHY_INTERFACE_MODE_SGMII;
		break;
545
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
546 547 548 549 550 551 552 553 554
		mode = PHY_INTERFACE_MODE_1000BASEX;
		break;
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		mode = PHY_INTERFACE_MODE_2500BASEX;
		break;
	default:
		mode = PHY_INTERFACE_MODE_NA;
	}

555
	err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
556
				       PAUSE_OFF, mode);
557 558 559 560 561
	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);
562 563 564
}

static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
565
					     u8 lane)
566 567 568 569 570 571 572 573
{
	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
				      MV88E6390_SGMII_INT_ENABLE,
				      MV88E6390_SGMII_INT_LINK_DOWN |
				      MV88E6390_SGMII_INT_LINK_UP);
}

static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
574
					      u8 lane)
575 576 577 578 579 580
{
	return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
				      MV88E6390_SGMII_INT_ENABLE, 0);
}

int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
581
				u8 lane)
582 583 584 585 586 587
{
	u8 cmode = chip->ports[port].cmode;
	int err = 0;

	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
588
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
589 590 591 592 593 594 595 596
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
	}

	return err;
}

int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
597
				 u8 lane)
598 599 600 601 602 603
{
	u8 cmode = chip->ports[port].cmode;
	int err = 0;

	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
604
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
605 606 607 608 609 610 611 612
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
	}

	return err;
}

static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
613
					     u8 lane, u16 *status)
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
{
	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;
631
	u8 lane;
632

633
	mv88e6xxx_reg_lock(chip);
634

635 636
	lane = mv88e6xxx_serdes_get_lane(chip, port->port);
	if (!lane)
637 638
		goto out;

639 640
	switch (cmode) {
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
641
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
642 643 644 645
	case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
		err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
		if (err)
			goto out;
646 647
		if (status & (MV88E6390_SGMII_INT_LINK_DOWN |
			      MV88E6390_SGMII_INT_LINK_UP)) {
648 649 650 651 652
			ret = IRQ_HANDLED;
			mv88e6390_serdes_irq_link_sgmii(chip, port->port, lane);
		}
	}
out:
653
	mv88e6xxx_reg_unlock(chip);
654 655 656 657

	return ret;
}

658 659 660 661 662
unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port)
{
	return irq_find_mapping(chip->g2_irq.domain, port);
}

663
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
664
{
665
	unsigned int irq;
666
	int err;
667
	u8 lane;
668

669 670 671
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
		return 0;
672

673 674
	irq = mv88e6xxx_serdes_irq_mapping(chip, port);
	if (!irq)
675
		return 0;
676

677 678
	chip->ports[port].serdes_irq = irq;

679 680 681
	/* Requesting the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
682
	mv88e6xxx_reg_unlock(chip);
683 684 685 686
	err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
				   mv88e6390_serdes_thread_fn,
				   IRQF_ONESHOT, "mv88e6xxx-serdes",
				   &chip->ports[port]);
687
	mv88e6xxx_reg_lock(chip);
688 689 690 691 692 693 694 695 696 697

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

	return mv88e6390_serdes_irq_enable(chip, port, lane);
}

698
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
699
{
700
	u8 lane;
701

702 703
	lane = mv88e6xxx_serdes_get_lane(chip, port);
	if (!lane)
704 705 706 707 708 709 710
		return;

	mv88e6390_serdes_irq_disable(chip, port, lane);

	/* Freeing the IRQ will trigger irq callbacks. So we cannot
	 * hold the reg_lock.
	 */
711
	mv88e6xxx_reg_unlock(chip);
712
	free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
713
	mv88e6xxx_reg_lock(chip);
714 715

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