Commit de776d0d authored by Pavana Sharma's avatar Pavana Sharma Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: add support for mv88e6393x family



The Marvell 88E6393X device is a single-chip integration of a 11-port
Ethernet switch with eight integrated Gigabit Ethernet (GbE)
transceivers and three 10-Gigabit interfaces.

This patch adds functionalities specific to mv88e6393x family (88E6393X,
88E6193X and 88E6191X).

The main differences between previous devices and this one are:
- port 0 can be a SERDES port
- all SERDESes are one-lane, eg. no XAUI nor RXAUI
- on the other hand the SERDESes can do USXGMII, 10GBASER and 5GBASER
  (on 6191X only one SERDES is capable of more than 1g; USXGMII is not
  yet supported with this change)
- Port Policy CTL register is changed to Port Policy MGMT CTL register,
  via which several more registers can be accessed indirectly
- egress monitor port is configured differently
- ingress monitor/CPU/mirror ports are configured differently and can be
  configured per port (ie. each port can have different ingress monitor
  port, for example)
- port speed AltBit works differently than previously
- PHY registers can be also accessed via MDIO address 0x18 and 0x19
  (on previous devices they could be accessed only via Global 2 offsets
   0x18 and 0x19, which means two indirections; this feature is not yet
   leveraged with thiis commit)

Co-developed-by: default avatarAshkan Boldaji <ashkan.boldaji@digi.com>
Signed-off-by: default avatarAshkan Boldaji <ashkan.boldaji@digi.com>
Signed-off-by: default avatarPavana Sharma <pavana.sharma@digi.com>
Co-developed-by: default avatarMarek Behún <kabel@kernel.org>
Signed-off-by: default avatarMarek Behún <kabel@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2fda45f0
Loading
Loading
Loading
Loading
+155 −0
Original line number Diff line number Diff line
@@ -635,6 +635,29 @@ static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
	mv88e6390_phylink_validate(chip, port, mask, state);
}

static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port,
					unsigned long *mask,
					struct phylink_link_state *state)
{
	if (port == 0 || port == 9 || port == 10) {
		phylink_set(mask, 10000baseT_Full);
		phylink_set(mask, 10000baseKR_Full);
		phylink_set(mask, 10000baseCR_Full);
		phylink_set(mask, 10000baseSR_Full);
		phylink_set(mask, 10000baseLR_Full);
		phylink_set(mask, 10000baseLRM_Full);
		phylink_set(mask, 10000baseER_Full);
		phylink_set(mask, 5000baseT_Full);
		phylink_set(mask, 2500baseX_Full);
		phylink_set(mask, 2500baseT_Full);
	}

	phylink_set(mask, 1000baseT_Full);
	phylink_set(mask, 1000baseX_Full);

	mv88e6065_phylink_validate(chip, port, mask, state);
}

static void mv88e6xxx_validate(struct dsa_switch *ds, int port,
			       unsigned long *supported,
			       struct phylink_link_state *state)
@@ -4589,6 +4612,69 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
	.phylink_validate = mv88e6390x_phylink_validate,
};

static const struct mv88e6xxx_ops mv88e6393x_ops = {
	/* MV88E6XXX_FAMILY_6393 */
	.setup_errata = mv88e6393x_serdes_setup_errata,
	.irl_init_all = mv88e6390_g2_irl_init_all,
	.get_eeprom = mv88e6xxx_g2_get_eeprom8,
	.set_eeprom = mv88e6xxx_g2_set_eeprom8,
	.set_switch_mac = mv88e6xxx_g2_set_switch_mac,
	.phy_read = mv88e6xxx_g2_smi_phy_read,
	.phy_write = mv88e6xxx_g2_smi_phy_write,
	.port_set_link = mv88e6xxx_port_set_link,
	.port_sync_link = mv88e6xxx_port_sync_link,
	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
	.port_tag_remap = mv88e6390_port_tag_remap,
	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
	.port_set_mcast_flood = mv88e6352_port_set_mcast_flood,
	.port_set_ether_type = mv88e6393x_port_set_ether_type,
	.port_set_jumbo_size = mv88e6165_port_set_jumbo_size,
	.port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
	.port_pause_limit = mv88e6390_port_pause_limit,
	.port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit,
	.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
	.port_get_cmode = mv88e6352_port_get_cmode,
	.port_set_cmode = mv88e6393x_port_set_cmode,
	.port_setup_message_port = mv88e6xxx_setup_message_port,
	.port_set_upstream_port = mv88e6393x_port_set_upstream_port,
	.stats_snapshot = mv88e6390_g1_stats_snapshot,
	.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
	.stats_get_sset_count = mv88e6320_stats_get_sset_count,
	.stats_get_strings = mv88e6320_stats_get_strings,
	.stats_get_stats = mv88e6390_stats_get_stats,
	/* .set_cpu_port is missing because this family does not support a global
	 * CPU port, only per port CPU port which is set via
	 * .port_set_upstream_port method.
	 */
	.set_egress_port = mv88e6393x_set_egress_port,
	.watchdog_ops = &mv88e6390_watchdog_ops,
	.mgmt_rsvd2cpu = mv88e6393x_port_mgmt_rsvd2cpu,
	.pot_clear = mv88e6xxx_g2_pot_clear,
	.reset = mv88e6352_g1_reset,
	.rmu_disable = mv88e6390_g1_rmu_disable,
	.atu_get_hash = mv88e6165_g1_atu_get_hash,
	.atu_set_hash = mv88e6165_g1_atu_set_hash,
	.vtu_getnext = mv88e6390_g1_vtu_getnext,
	.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
	.serdes_power = mv88e6393x_serdes_power,
	.serdes_get_lane = mv88e6393x_serdes_get_lane,
	.serdes_pcs_get_state = mv88e6393x_serdes_pcs_get_state,
	.serdes_pcs_config = mv88e6390_serdes_pcs_config,
	.serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart,
	.serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up,
	.serdes_irq_mapping = mv88e6390_serdes_irq_mapping,
	.serdes_irq_enable = mv88e6393x_serdes_irq_enable,
	.serdes_irq_status = mv88e6393x_serdes_irq_status,
	/* TODO: serdes stats */
	.gpio_ops = &mv88e6352_gpio_ops,
	.avb_ops = &mv88e6390_avb_ops,
	.ptp_ops = &mv88e6352_ptp_ops,
	.phylink_validate = mv88e6393x_phylink_validate,
};

static const struct mv88e6xxx_info mv88e6xxx_table[] = {
	[MV88E6085] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
@@ -4960,6 +5046,52 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
		.ops = &mv88e6191_ops,
	},

	[MV88E6191X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6191X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.tag_protocol = DSA_TAG_PROTO_DSA,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},

	[MV88E6193X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6193X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6193X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.tag_protocol = DSA_TAG_PROTO_DSA,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},

	[MV88E6220] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6220,
		.family = MV88E6XXX_FAMILY_6250,
@@ -5250,6 +5382,29 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
		.ptp_support = true,
		.ops = &mv88e6390x_ops,
	},

	[MV88E6393X] = {
		.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X,
		.family = MV88E6XXX_FAMILY_6393,
		.name = "Marvell 88E6393X",
		.num_databases = 4096,
		.num_ports = 11,	/* 10 + Z80 */
		.num_internal_phys = 9,
		.max_vid = 8191,
		.port_base_addr = 0x0,
		.phy_base_addr = 0x0,
		.global1_addr = 0x1b,
		.global2_addr = 0x1c,
		.age_time_coeff = 3750,
		.g1_irqs = 10,
		.g2_irqs = 14,
		.atu_move_port_mask = 0x1f,
		.pvt = true,
		.multi_chip = true,
		.tag_protocol = DSA_TAG_PROTO_DSA,
		.ptp_support = true,
		.ops = &mv88e6393x_ops,
	},
};

static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num)
+4 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ enum mv88e6xxx_model {
	MV88E6190,
	MV88E6190X,
	MV88E6191,
	MV88E6191X,
	MV88E6193X,
	MV88E6220,
	MV88E6240,
	MV88E6250,
@@ -75,6 +77,7 @@ enum mv88e6xxx_model {
	MV88E6352,
	MV88E6390,
	MV88E6390X,
	MV88E6393X,
};

enum mv88e6xxx_family {
@@ -90,6 +93,7 @@ enum mv88e6xxx_family {
	MV88E6XXX_FAMILY_6351,	/* 6171 6175 6350 6351 */
	MV88E6XXX_FAMILY_6352,	/* 6172 6176 6240 6352 */
	MV88E6XXX_FAMILY_6390,  /* 6190 6190X 6191 6290 6390 6390X */
	MV88E6XXX_FAMILY_6393,	/* 6191X 6193X 6393X */
};

struct mv88e6xxx_ops;
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#define MV88E6185_G1_STS_PPU_STATE_DISABLED		0x8000
#define MV88E6185_G1_STS_PPU_STATE_POLLING		0xc000
#define MV88E6XXX_G1_STS_INIT_READY			0x0800
#define MV88E6393X_G1_STS_IRQ_DEVICE_2			9
#define MV88E6XXX_G1_STS_IRQ_AVB			8
#define MV88E6XXX_G1_STS_IRQ_DEVICE			7
#define MV88E6XXX_G1_STS_IRQ_STATS			6
@@ -59,6 +60,7 @@
#define MV88E6185_G1_CTL1_SCHED_PRIO		0x0800
#define MV88E6185_G1_CTL1_MAX_FRAME_1632	0x0400
#define MV88E6185_G1_CTL1_RELOAD_EEPROM		0x0200
#define MV88E6393X_G1_CTL1_DEVICE2_EN		0x0200
#define MV88E6XXX_G1_CTL1_DEVICE_EN		0x0080
#define MV88E6XXX_G1_CTL1_STATS_DONE_EN		0x0040
#define MV88E6XXX_G1_CTL1_VTU_PROBLEM_EN	0x0020
+8 −0
Original line number Diff line number Diff line
@@ -38,9 +38,15 @@
/* Offset 0x02: MGMT Enable Register 2x */
#define MV88E6XXX_G2_MGMT_EN_2X		0x02

/* Offset 0x02: MAC LINK change IRQ Register for MV88E6393X */
#define MV88E6393X_G2_MACLINK_INT_SRC		0x02

/* Offset 0x03: MGMT Enable Register 0x */
#define MV88E6XXX_G2_MGMT_EN_0X		0x03

/* Offset 0x03: MAC LINK change IRQ Mask Register for MV88E6393X */
#define MV88E6393X_G2_MACLINK_INT_MASK		0x03

/* Offset 0x04: Flow Control Delay Register */
#define MV88E6XXX_G2_FLOW_CTL	0x04

@@ -52,6 +58,8 @@
#define MV88E6XXX_G2_SWITCH_MGMT_FORCE_FLOW_CTL_PRI	0x0080
#define MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU		0x0008

#define MV88E6393X_G2_EGRESS_MONITOR_DEST		0x05

/* Offset 0x06: Device Mapping Table Register */
#define MV88E6XXX_G2_DEVICE_MAPPING		0x06
#define MV88E6XXX_G2_DEVICE_MAPPING_UPDATE	0x8000
+267 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/phylink.h>

#include "chip.h"
#include "global2.h"
#include "port.h"
#include "serdes.h"

@@ -25,6 +26,14 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
	return mv88e6xxx_read(chip, addr, reg, val);
}

int mv88e6xxx_port_wait_bit(struct mv88e6xxx_chip *chip, int port, int reg,
			    int bit, int val)
{
	int addr = chip->info->port_base_addr + port;

	return mv88e6xxx_wait_bit(chip, addr, reg, bit, val);
}

int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
			 u16 val)
{
@@ -426,6 +435,106 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
	return PHY_INTERFACE_MODE_NA;
}

/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)
 * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
 * values for speeds 2500 & 5000 conflict.
 */
int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
				     int speed, int duplex)
{
	u16 reg, ctrl;
	int err;

	if (speed == SPEED_MAX)
		speed = (port > 0 && port < 9) ? 1000 : 10000;

	if (speed == 200 && port != 0)
		return -EOPNOTSUPP;

	if (speed >= 2500 && port > 0 && port < 9)
		return -EOPNOTSUPP;

	switch (speed) {
	case 10:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
		break;
	case 100:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
		break;
	case 200:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
			MV88E6390_PORT_MAC_CTL_ALTSPEED;
		break;
	case 1000:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
		break;
	case 2500:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000 |
			MV88E6390_PORT_MAC_CTL_ALTSPEED;
		break;
	case 5000:
		ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
			MV88E6390_PORT_MAC_CTL_ALTSPEED;
		break;
	case 10000:
	case SPEED_UNFORCED:
		ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
		break;
	default:
		return -EOPNOTSUPP;
	}

	switch (duplex) {
	case DUPLEX_HALF:
		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
		break;
	case DUPLEX_FULL:
		ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
			MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
		break;
	case DUPLEX_UNFORCED:
		/* normal duplex detection */
		break;
	default:
		return -EOPNOTSUPP;
	}

	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
	if (err)
		return err;

	reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK |
		 MV88E6390_PORT_MAC_CTL_ALTSPEED |
		 MV88E6390_PORT_MAC_CTL_FORCE_SPEED);

	if (speed != SPEED_UNFORCED)
		reg |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;

	reg |= ctrl;

	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
	if (err)
		return err;

	if (speed)
		dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
	else
		dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
	dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
		reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
		reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");

	return 0;
}

phy_interface_t mv88e6393x_port_max_speed_mode(int port)
{
	if (port == 0 || port == 9 || port == 10)
		return PHY_INTERFACE_MODE_10GBASER;

	return PHY_INTERFACE_MODE_NA;
}

static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
				    phy_interface_t mode, bool force)
{
@@ -450,6 +559,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	case PHY_INTERFACE_MODE_2500BASEX:
		cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
		break;
	case PHY_INTERFACE_MODE_5GBASER:
		cmode = MV88E6393X_PORT_STS_CMODE_5GBASER;
		break;
	case PHY_INTERFACE_MODE_XGMII:
	case PHY_INTERFACE_MODE_XAUI:
		cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
@@ -457,6 +569,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	case PHY_INTERFACE_MODE_RXAUI:
		cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
		break;
	case PHY_INTERFACE_MODE_10GBASER:
		cmode = MV88E6393X_PORT_STS_CMODE_10GBASER;
		break;
	default:
		cmode = 0;
	}
@@ -541,6 +656,29 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
	return mv88e6xxx_port_set_cmode(chip, port, mode, false);
}

int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
			      phy_interface_t mode)
{
	int err;
	u16 reg;

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

	/* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */
	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
	if (err)
		return err;

	reg &= ~MV88E6XXX_PORT_MAC_CTL_EEE;
	reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_EEE;
	err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
	if (err)
		return err;

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

static int mv88e6341_port_set_cmode_writable(struct mv88e6xxx_chip *chip,
					     int port)
{
@@ -1185,6 +1323,135 @@ int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port)
	return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_PRI_OVERRIDE, 0);
}

/* Offset 0x0E: Policy & MGMT Control Register for FAMILY 6191X 6193X 6393X */

static int mv88e6393x_port_policy_write(struct mv88e6xxx_chip *chip, int port,
					u16 pointer, u8 data)
{
	u16 reg;

	reg = MV88E6393X_PORT_POLICY_MGMT_CTL_UPDATE | pointer | data;

	return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_POLICY_MGMT_CTL,
				    reg);
}

static int mv88e6393x_port_policy_write_all(struct mv88e6xxx_chip *chip,
					    u16 pointer, u8 data)
{
	int err, port;

	for (port = 0; port < mv88e6xxx_num_ports(chip); port++) {
		if (dsa_is_unused_port(chip->ds, port))
			continue;

		err = mv88e6393x_port_policy_write(chip, port, pointer, data);
		if (err)
			return err;
	}

	return 0;
}

int mv88e6393x_set_egress_port(struct mv88e6xxx_chip *chip,
			       enum mv88e6xxx_egress_direction direction,
			       int port)
{
	u16 ptr;
	int err;

	switch (direction) {
	case MV88E6XXX_EGRESS_DIR_INGRESS:
		ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_INGRESS_DEST;
		err = mv88e6393x_port_policy_write_all(chip, ptr, port);
		if (err)
			return err;
		break;
	case MV88E6XXX_EGRESS_DIR_EGRESS:
		ptr = MV88E6393X_G2_EGRESS_MONITOR_DEST;
		err = mv88e6xxx_g2_write(chip, ptr, port);
		if (err)
			return err;
		break;
	}

	return 0;
}

int mv88e6393x_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
				      int upstream_port)
{
	u16 ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_CPU_DEST;
	u8 data = MV88E6393X_PORT_POLICY_MGMT_CTL_CPU_DEST_MGMTPRI |
		  upstream_port;

	return mv88e6393x_port_policy_write(chip, port, ptr, data);
}

int mv88e6393x_port_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
{
	u16 ptr;
	int err;

	/* Consider the frames with reserved multicast destination
	 * addresses matching 01:80:c2:00:00:00 and
	 * 01:80:c2:00:00:02 as MGMT.
	 */
	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XLO;
	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
	if (err)
		return err;

	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000000XHI;
	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
	if (err)
		return err;

	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XLO;
	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
	if (err)
		return err;

	ptr = MV88E6393X_PORT_POLICY_MGMT_CTL_PTR_01C280000002XHI;
	err = mv88e6393x_port_policy_write_all(chip, ptr, 0xff);
	if (err)
		return err;

	return 0;
}

/* Offset 0x10 & 0x11: EPC */

static int mv88e6393x_port_epc_wait_ready(struct mv88e6xxx_chip *chip, int port)
{
	int bit = __bf_shf(MV88E6393X_PORT_EPC_CMD_BUSY);

	return mv88e6xxx_port_wait_bit(chip, port, MV88E6393X_PORT_EPC_CMD, bit, 0);
}

/* Port Ether type for 6393X family */

int mv88e6393x_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
				   u16 etype)
{
	u16 val;
	int err;

	err = mv88e6393x_port_epc_wait_ready(chip, port);
	if (err)
		return err;

	err = mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_DATA, etype);
	if (err)
		return err;

	val = MV88E6393X_PORT_EPC_CMD_BUSY |
	      MV88E6393X_PORT_EPC_CMD_WRITE |
	      MV88E6393X_PORT_EPC_INDEX_PORT_ETYPE;

	return mv88e6xxx_port_write(chip, port, MV88E6393X_PORT_EPC_CMD, val);
}

/* Offset 0x0f: Port Ether type */

int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
Loading