Commit 0e5c9ab3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-dsa-mv88e6xxx-Peridot-Topaz-SERDES-changes'



Marek Behún says:

====================
net: dsa: mv88e6xxx: Peridot/Topaz SERDES changes

this is the fifth version of changes for the Topaz/Peridot family of
switches. The patches apply on net-next.
Changes since v4:
 - added Reviewed-by and Tested-by tags on first 2 patches, the others
   are changed are affected by changes in patch 3/6, so I did not add
   the tags, except for 5/6, which is just macro renaming
 - patch 3 was changed: the serdes_get_lane returns 0 on success (lane
   was discovered), -ENODEV if not lane is present on the port, and
   other error if other error occured. Lane is put into a pointer of
   type u8
 - patches 4 and 6 were affected by this (error detecting from
   serdes_get_lane)
 - Andrew's complaint about the two additional parameters
   (allow_over_2500 and make_cmode_writable) was addressed, by Vivien's
   advice: I put a new method into chip operations structure, named
   port_set_cmode_writable. This is called from mv88e6xxx_port_setup_mac
   just before port_set_cmode. The method is implemented for Topaz.
   The check if cmodes over 2500 should be allowed on given port is now
   done in the specific port_set_cmode() that requires it, thus the
   allow_over_2500 argument is not needed

Again, tested on Turris Mox with Peridot, Topaz, and Peridot + Topaz.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e93b4f03 7a3007d2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o
+32 −64
Original line number Diff line number Diff line
@@ -454,6 +454,12 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
			goto restore_link;
	}

	if (chip->info->ops->port_set_cmode_writable) {
		err = chip->info->ops->port_set_cmode_writable(chip, port);
		if (err && err != -EOPNOTSUPP)
			goto restore_link;
	}

	if (chip->info->ops->port_set_cmode) {
		err = chip->info->ops->port_set_cmode(chip, port, mode);
		if (err && err != -EOPNOTSUPP)
@@ -2317,60 +2323,6 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
	return mv88e6xxx_g1_stats_clear(chip);
}

/* The mv88e6390 has some hidden registers used for debug and
 * development. The errata also makes use of them.
 */
static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port,
				  int reg, u16 val)
{
	u16 ctrl;
	int err;

	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT,
				   PORT_RESERVED_1A, val);
	if (err)
		return err;

	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE |
	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
	       reg;

	return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
				    PORT_RESERVED_1A, ctrl);
}

static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip)
{
	int bit = __bf_shf(PORT_RESERVED_1A_BUSY);

	return mv88e6xxx_wait_bit(chip, PORT_RESERVED_1A_CTRL_PORT,
				  PORT_RESERVED_1A, bit, 0);
}


static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port,
				  int reg, u16 *val)
{
	u16 ctrl;
	int err;

	ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ |
	       PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT |
	       reg;

	err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT,
				   PORT_RESERVED_1A, ctrl);
	if (err)
		return err;

	err = mv88e6390_hidden_wait(chip);
	if (err)
		return err;

	return 	mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT,
				    PORT_RESERVED_1A, val);
}

/* Check if the errata has already been applied. */
static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
{
@@ -2379,7 +2331,7 @@ static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
	u16 val;

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		err = mv88e6390_hidden_read(chip, port, 0, &val);
		err = mv88e6xxx_port_hidden_read(chip, 0xf, port, 0, &val);
		if (err) {
			dev_err(chip->dev,
				"Error reading hidden register: %d\n", err);
@@ -2412,7 +2364,7 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
	}

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		err = mv88e6390_hidden_write(chip, port, 0, 0x01c0);
		err = mv88e6xxx_port_hidden_write(chip, 0xf, port, 0, 0x01c0);
		if (err)
			return err;
	}
@@ -2967,6 +2919,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.port_link_state = mv88e6352_port_link_state,
	.port_get_cmode = mv88e6352_port_get_cmode,
	.port_set_cmode_writable = mv88e6341_port_set_cmode_writable,
	.port_set_cmode = mv88e6341_port_set_cmode,
	.port_setup_message_port = mv88e6xxx_setup_message_port,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
@@ -2981,7 +2935,10 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
	.reset = mv88e6352_g1_reset,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_power = mv88e6341_serdes_power,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6341_phylink_validate,
};
@@ -3309,6 +3266,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
@@ -3354,9 +3312,10 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
	.rmu_disable = mv88e6390_g1_rmu_disable,
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390x_serdes_power,
	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
	.serdes_irq_free = mv88e6390x_serdes_irq_free,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
	.phylink_validate = mv88e6390x_phylink_validate,
};
@@ -3401,6 +3360,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.avb_ops = &mv88e6390_avb_ops,
@@ -3537,6 +3497,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
@@ -3657,6 +3618,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.port_link_state = mv88e6352_port_link_state,
	.port_get_cmode = mv88e6352_port_get_cmode,
	.port_set_cmode_writable = mv88e6341_port_set_cmode_writable,
	.port_set_cmode = mv88e6341_port_set_cmode,
	.port_setup_message_port = mv88e6xxx_setup_message_port,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
@@ -3671,7 +3634,10 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
	.reset = mv88e6352_g1_reset,
	.vtu_getnext = mv88e6352_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
	.serdes_power = mv88e6341_serdes_power,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6341_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
@@ -3854,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
@@ -3903,9 +3870,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
	.rmu_disable = mv88e6390_g1_rmu_disable,
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6390x_serdes_power,
	.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
	.serdes_irq_free = mv88e6390x_serdes_irq_free,
	.serdes_power = mv88e6390_serdes_power,
	.serdes_get_lane = mv88e6390x_serdes_get_lane,
	.serdes_irq_setup = mv88e6390_serdes_irq_setup,
	.serdes_irq_free = mv88e6390_serdes_irq_free,
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
+4 −0
Original line number Diff line number Diff line
@@ -400,6 +400,7 @@ struct mv88e6xxx_ops {
	/* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc.
	 * Some chips allow this to be configured on specific ports.
	 */
	int (*port_set_cmode_writable)(struct mv88e6xxx_chip *chip, int port);
	int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port,
			      phy_interface_t mode);
	int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
@@ -443,6 +444,9 @@ struct mv88e6xxx_ops {
	/* Power on/off a SERDES interface */
	int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on);

	/* SERDES lane mapping */
	int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port, u8 *lane);

	/* SERDES interrupt handling */
	int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
	void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);
+71 −18
Original line number Diff line number Diff line
@@ -392,17 +392,14 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
	return PHY_INTERFACE_MODE_NA;
}

int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
				    phy_interface_t mode)
{
	int lane;
	u8 lane;
	u16 cmode;
	u16 reg;
	int err;

	if (port != 9 && port != 10)
		return -EOPNOTSUPP;

	/* Default to a slow mode, so freeing up SERDES interfaces for
	 * other ports which might use them for SFPs.
	 */
@@ -411,7 +408,7 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,

	switch (mode) {
	case PHY_INTERFACE_MODE_1000BASEX:
		cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
		cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
		break;
	case PHY_INTERFACE_MODE_SGMII:
		cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
@@ -434,18 +431,18 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	if (cmode == chip->ports[port].cmode)
		return 0;

	lane = mv88e6390x_serdes_get_lane(chip, port);
	if (lane < 0 && lane != -ENODEV)
		return lane;
	err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
	if (err && err != -ENODEV)
		return err;

	if (lane >= 0) {
	if (err != -ENODEV) {
		if (chip->ports[port].serdes_irq) {
			err = mv88e6390_serdes_irq_disable(chip, port, lane);
			if (err)
				return err;
		}

		err = mv88e6390x_serdes_power(chip, port, false);
		err = mv88e6390_serdes_power(chip, port, false);
		if (err)
			return err;
	}
@@ -466,11 +463,11 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,

		chip->ports[port].cmode = cmode;

		lane = mv88e6390x_serdes_get_lane(chip, port);
		if (lane < 0)
			return lane;
		err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
		if (err)
			return err;

		err = mv88e6390x_serdes_power(chip, port, true);
		err = mv88e6390_serdes_power(chip, port, true);
		if (err)
			return err;

@@ -484,9 +481,65 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	return 0;
}

int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			      phy_interface_t mode)
{
	if (port != 9 && port != 10)
		return -EOPNOTSUPP;

	return mv88e6xxx_port_set_cmode(chip, port, mode);
}

int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			     phy_interface_t mode)
{
	if (port != 9 && port != 10)
		return -EOPNOTSUPP;

	switch (mode) {
	case PHY_INTERFACE_MODE_NA:
		return 0;
	case PHY_INTERFACE_MODE_XGMII:
	case PHY_INTERFACE_MODE_XAUI:
	case PHY_INTERFACE_MODE_RXAUI:
		return -EINVAL;
	default:
		break;
	}

	return mv88e6xxx_port_set_cmode(chip, port, mode);
}

int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip, int port)
{
	int err, addr;
	u16 reg, bits;

	if (port != 5)
		return -EOPNOTSUPP;

	addr = chip->info->port_base_addr + port;

	err = mv88e6xxx_port_hidden_read(chip, 0x7, addr, 0, &reg);
	if (err)
		return err;

	bits = MV88E6341_PORT_RESERVED_1A_FORCE_CMODE |
	       MV88E6341_PORT_RESERVED_1A_SGMII_AN;

	if ((reg & bits) == bits)
		return 0;

	reg |= bits;
	return mv88e6xxx_port_hidden_write(chip, 0x7, addr, 0, reg);
}

int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			     phy_interface_t mode)
{
	if (port != 5)
		return -EOPNOTSUPP;

	switch (mode) {
	case PHY_INTERFACE_MODE_NA:
		return 0;
@@ -498,7 +551,7 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
		break;
	}

	return mv88e6390x_port_set_cmode(chip, port, mode);
	return mv88e6xxx_port_set_cmode(chip, port, mode);
}

int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
@@ -618,7 +671,7 @@ int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
		else
			state->interface = PHY_INTERFACE_MODE_RGMII;
		break;
	case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
	case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
		state->interface = PHY_INTERFACE_MODE_1000BASEX;
		break;
	case MV88E6XXX_PORT_STS_CMODE_SGMII:
+21 −10
Original line number Diff line number Diff line
@@ -43,8 +43,8 @@
#define MV88E6XXX_PORT_STS_FLOW_CTL		0x0010
#define MV88E6XXX_PORT_STS_CMODE_MASK		0x000f
#define MV88E6XXX_PORT_STS_CMODE_RGMII		0x0007
#define MV88E6XXX_PORT_STS_CMODE_100BASE_X	0x0008
#define MV88E6XXX_PORT_STS_CMODE_1000BASE_X	0x0009
#define MV88E6XXX_PORT_STS_CMODE_100BASEX	0x0008
#define MV88E6XXX_PORT_STS_CMODE_1000BASEX	0x0009
#define MV88E6XXX_PORT_STS_CMODE_SGMII		0x000a
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX	0x000b
#define MV88E6XXX_PORT_STS_CMODE_XAUI		0x000c
@@ -261,14 +261,16 @@
#define MV88E6095_PORT_IEEE_PRIO_REMAP_4567	0x19

/* Offset 0x1a: Magic undocumented errata register */
#define PORT_RESERVED_1A			0x1a
#define PORT_RESERVED_1A_BUSY			BIT(15)
#define PORT_RESERVED_1A_WRITE			BIT(14)
#define PORT_RESERVED_1A_READ			0
#define PORT_RESERVED_1A_PORT_SHIFT		5
#define PORT_RESERVED_1A_BLOCK			(0xf << 10)
#define PORT_RESERVED_1A_CTRL_PORT		4
#define PORT_RESERVED_1A_DATA_PORT		5
#define MV88E6XXX_PORT_RESERVED_1A		0x1a
#define MV88E6XXX_PORT_RESERVED_1A_BUSY		0x8000
#define MV88E6XXX_PORT_RESERVED_1A_WRITE	0x4000
#define MV88E6XXX_PORT_RESERVED_1A_READ		0x0000
#define MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT	5
#define MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT	10
#define MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT	0x04
#define MV88E6XXX_PORT_RESERVED_1A_DATA_PORT	0x05
#define MV88E6341_PORT_RESERVED_1A_FORCE_CMODE	0x8000
#define MV88E6341_PORT_RESERVED_1A_SGMII_AN	0x2000

int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
			u16 *val);
@@ -334,6 +336,9 @@ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
			       u8 out);
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
			       u8 out);
int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip, int port);
int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			     phy_interface_t mode);
int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			     phy_interface_t mode);
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
@@ -353,4 +358,10 @@ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port);
int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port);

int mv88e6xxx_port_hidden_write(struct mv88e6xxx_chip *chip, int block,
				int port, int reg, u16 val);
int mv88e6xxx_port_hidden_wait(struct mv88e6xxx_chip *chip);
int mv88e6xxx_port_hidden_read(struct mv88e6xxx_chip *chip, int block, int port,
			       int reg, u16 *val);

#endif /* _MV88E6XXX_PORT_H */
Loading