int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
u16 val)
{ int addr = chip->info->port_base_addr + port;
return mv88e6xxx_write(chip, addr, reg, val);
}
/* Offset 0x00: MAC (or PCS or Physical) Status Register * * For most devices, this is read only. However the 6185 has the MyPause * bit read/write.
*/ int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port, int pause)
{
u16 reg; int err;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err;
if (pause)
reg |= MV88E6XXX_PORT_STS_MY_PAUSE; else
reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
/* Offset 0x01: MAC (or PCS or Physical) Control Register * * Link, Duplex and Flow Control have one force bit, one value bit. * * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value. * Alternative values require the 200BASE (or AltSpeed) bit 12 set. * Newer chips need a ForcedSpd bit 13 set to consider the value.
*/
staticint mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
{
u16 reg; int err;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err;
int mv88e6320_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
{ if (port != 2 && port != 5 && port != 6) return -EOPNOTSUPP;
int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsignedint mode, bool isup)
{ conststruct mv88e6xxx_ops *ops = chip->info->ops; int err = 0; int link;
if (isup)
link = LINK_FORCED_UP; else
link = LINK_FORCED_DOWN;
if (ops->port_set_link)
err = ops->port_set_link(chip, port, link);
return err;
}
int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsignedint mode, bool isup)
{ conststruct mv88e6xxx_ops *ops = chip->info->ops; int err = 0; int link;
if (mode == MLO_AN_INBAND)
link = LINK_UNFORCED; elseif (isup)
link = LINK_FORCED_UP; else
link = LINK_FORCED_DOWN;
if (ops->port_set_link)
err = ops->port_set_link(chip, port, link);
return err;
}
staticint mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, bool alt_bit, bool force_bit, int duplex)
{
u16 reg, ctrl; int err;
switch (speed) { case 10:
ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10; break; case 100:
ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100; break; case 200: if (alt_bit)
ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
MV88E6390_PORT_MAC_CTL_ALTSPEED; else
ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200; break; case 1000:
ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; break; case 2500: if (alt_bit)
ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
MV88E6390_PORT_MAC_CTL_ALTSPEED; else
ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000; break; case 10000: /* all bits set, fall through... */ 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, ®); if (err) return err;
/* Support 10, 100 Mbps (e.g. 88E6250 family) */ int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex)
{ if (speed > 100) return -EOPNOTSUPP;
/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex)
{ if (speed > 2500) return -EOPNOTSUPP;
if (speed == 200 && port != 0) return -EOPNOTSUPP;
if (speed == 2500 && port < 5) return -EOPNOTSUPP;
phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip, int port)
{ if (port == 5) return PHY_INTERFACE_MODE_2500BASEX;
return PHY_INTERFACE_MODE_NA;
}
/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex)
{ if (speed > 1000) return -EOPNOTSUPP;
/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex)
{ if (speed > 2500) return -EOPNOTSUPP;
if (speed == 200 && port != 0) return -EOPNOTSUPP;
if (speed == 2500 && port < 9) return -EOPNOTSUPP;
phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip, int port)
{ if (port == 9 || port == 10) return PHY_INTERFACE_MODE_2500BASEX;
return PHY_INTERFACE_MODE_NA;
}
/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex)
{ if (speed == 200 && port != 0) return -EOPNOTSUPP;
if (speed >= 2500 && port < 9) return -EOPNOTSUPP;
phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip, int port)
{ if (port == 9 || port == 10) return PHY_INTERFACE_MODE_XAUI;
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 (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 &&
speed > 2500) return -EOPNOTSUPP;
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, ®); if (err) return err;
phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip, int port)
{
if (port != 0 && port != 9 && port != 10) return PHY_INTERFACE_MODE_NA;
if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361) return PHY_INTERFACE_MODE_2500BASEX;
return PHY_INTERFACE_MODE_10GBASER;
}
staticint mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode, bool force)
{
u16 cmode;
u16 reg; int err;
/* Default to a slow mode, so freeing up SERDES interfaces for * other ports which might use them for SFPs.
*/ if (mode == PHY_INTERFACE_MODE_NA)
mode = PHY_INTERFACE_MODE_1000BASEX;
switch (mode) { case PHY_INTERFACE_MODE_RMII:
cmode = MV88E6XXX_PORT_STS_CMODE_RMII; break; case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID:
cmode = MV88E6XXX_PORT_STS_CMODE_RGMII; break; case PHY_INTERFACE_MODE_1000BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX; break; case PHY_INTERFACE_MODE_SGMII:
cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; break; 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; break; case PHY_INTERFACE_MODE_RXAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; break; case PHY_INTERFACE_MODE_10GBASER:
cmode = MV88E6393X_PORT_STS_CMODE_10GBASER; break; case PHY_INTERFACE_MODE_USXGMII:
cmode = MV88E6393X_PORT_STS_CMODE_USXGMII; break; default:
cmode = 0;
}
/* cmode doesn't change, nothing to do for us unless forced */ if (cmode == chip->ports[port].cmode && !force) return 0;
chip->ports[port].cmode = 0;
if (cmode) {
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err;
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;
}
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;
if (port == 9 || port == 10) { switch (mode) { case PHY_INTERFACE_MODE_RMII: case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: return -EINVAL; default: break;
}
}
/* mv88e6393x errata 4.5: EEE should be disabled on SERDES ports */
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err;
int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
{ int err;
if (port != 5) 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;
}
err = mv88e6341_port_set_cmode_writable(chip, port); if (err) return err;
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
{ int err;
u16 reg;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err;
*cmode = reg & MV88E6185_PORT_STS_CMODE_MASK;
return 0;
}
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
{ int err;
u16 reg;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) return err;
*cmode = reg & MV88E6XXX_PORT_STS_CMODE_MASK;
return 0;
}
/* Offset 0x02: Jamming Control * * Do not limit the period of time that this port can be paused for by * the remote end or the period of time that this port can pause the * remote end.
*/ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
u8 out)
{ return mv88e6xxx_port_write(chip, port, MV88E6097_PORT_JAM_CTL,
out << 8 | in);
}
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
u8 out)
{ int err;
int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
{
u16 reg; int err;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err;
reg &= ~MV88E6XXX_PORT_CTL0_STATE_MASK;
switch (state) { case BR_STATE_DISABLED:
state = MV88E6XXX_PORT_CTL0_STATE_DISABLED; break; case BR_STATE_BLOCKING: case BR_STATE_LISTENING:
state = MV88E6XXX_PORT_CTL0_STATE_BLOCKING; break; case BR_STATE_LEARNING:
state = MV88E6XXX_PORT_CTL0_STATE_LEARNING; break; case BR_STATE_FORWARDING:
state = MV88E6XXX_PORT_CTL0_STATE_FORWARDING; break; default: return -EINVAL;
}
reg |= state;
err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); if (err) return err;
dev_dbg(chip->dev, "p%d: PortState set to %s\n", port,
mv88e6xxx_port_state_names[state]);
return 0;
}
int mv88e6xxx_port_set_egress_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_egress_mode mode)
{ int err;
u16 reg;
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); if (err) return err;
reg &= ~MV88E6XXX_PORT_CTL0_EGRESS_MODE_MASK;
switch (mode) { case MV88E6XXX_EGRESS_MODE_UNMODIFIED:
reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNMODIFIED; break; case MV88E6XXX_EGRESS_MODE_UNTAGGED:
reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_UNTAGGED; break; case MV88E6XXX_EGRESS_MODE_TAGGED:
reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_TAGGED; break; case MV88E6XXX_EGRESS_MODE_ETHERTYPE:
reg |= MV88E6XXX_PORT_CTL0_EGRESS_MODE_ETHER_TYPE_DSA; break; default: return -EINVAL;
}
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;
int mv88e6351_port_set_ether_type(struct mv88e6xxx_chip *chip, int port,
u16 etype)
{ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ETH_TYPE, etype);
}
/* Offset 0x18: Port IEEE Priority Remapping Registers [0-3] * Offset 0x19: Port IEEE Priority Remapping Registers [4-7]
*/
int mv88e6095_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
{ int err;
/* Use a direct priority mapping for all IEEE tagged frames */
err = mv88e6xxx_port_write(chip, port,
MV88E6095_PORT_IEEE_PRIO_REMAP_0123,
0x3210); if (err) return err;
int mv88e6390_port_tag_remap(struct mv88e6xxx_chip *chip, int port)
{ int err, i;
u16 table;
for (i = 0; i <= 7; i++) {
table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_INGRESS_PCP;
err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i,
(i | i << 4)); if (err) return err;
table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_GREEN_PCP;
err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err;
table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_YELLOW_PCP;
err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err;
table = MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_EGRESS_AVB_PCP;
err = mv88e6xxx_port_ieeepmt_write(chip, port, table, i, i); if (err) return err;
}
/* The 16-bit Port Policy CTL register from older chips is on 6393x * changed to Port Policy MGMT CTL, which can access more data, but * indirectly. The original 16-bit value is divided into two 8-bit * registers.
*/
ptr = shift / 8;
shift %= 8;
mask >>= ptr * 8;
ptr <<= 8;
err = mv88e6393x_port_policy_read(chip, port, ptr, ®); if (err) return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.