Commit c23515ad authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-dsa-mv88e6xxx-add-88e6361-support'

Alexis Lothoré says:

====================
net: dsa: mv88e6xxx: add 88E6361 support

This series brings initial support for Marvell 88E6361 switch.

MV88E6361 is a 8 ports switch with 5 integrated Gigabit PHYs and 3
2.5Gigabit SerDes interfaces. It is in fact a new variant in the
88E639X/88E6193X/88E6191X family with a subset of existing features:
- port 0: MII, RMII, RGMII, 1000BaseX, 2500BaseX
- port 3 to 7: triple speed internal phys
- port 9 and 10: 1000BaseX, 25000BaseX

Since said family is already well supported in mv88e6xxx driver, adding
initial support for this new switch mostly consists in finding the ID
exposed in its identification register, adding a proper description
in switch description tables in mv88e6xxx driver, and enforcing 88E6361
specificities in mv88e6393x_XXX methods.

- first 4 commits introduce an internal phy offset field for switches which
  have internal phys but not starting from port 0
- 5th commit is a fix on existing switches based on first commits
- 6th commit is a slight modification to prepare 886361 support
- last commit introduces 88E6361 support in 88E6393X family

This initial support has been tested with two samples of a custom board
with the following hardware configuration:
- a main CPU connected to MV88E6361 using port 0 as CPU port
- port 9 wired to a SFP cage
- port 10 wired to a G.Hn transceiver

The following setup was used:
PC <-ethernet-> (copper SFP) - Board 1 - (G.hn) <-phone line(RJ11)-> (G.hn) Board 2

The unit 1 has been configured to bridge SFP port and G.hn port together,
which allowed to successfully ping Board 2 from PC.
====================

Link: https://lore.kernel.org/r/20230529080246.82953-1-alexis.lothore@bootlin.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents e180a33c 12899f29
...@@ -20,7 +20,7 @@ which is at a different MDIO base address in different switch families. ...@@ -20,7 +20,7 @@ which is at a different MDIO base address in different switch families.
6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321,
6341, 6350, 6351, 6352 6341, 6350, 6351, 6352
- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: - "marvell,mv88e6190" : Switch has base address 0x00. Use with models:
6190, 6190X, 6191, 6290, 6390, 6390X 6163, 6190, 6190X, 6191, 6290, 6390, 6390X
- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: - "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model:
6220, 6250 6220, 6250
......
...@@ -463,11 +463,11 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, ...@@ -463,11 +463,11 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
return err; return err;
} }
static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) static int mv88e6xxx_phy_is_internal(struct mv88e6xxx_chip *chip, int port)
{ {
struct mv88e6xxx_chip *chip = ds->priv; return port >= chip->info->internal_phys_offset &&
port < chip->info->num_internal_phys +
return port < chip->info->num_internal_phys; chip->info->internal_phys_offset;
} }
static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
...@@ -479,7 +479,7 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) ...@@ -479,7 +479,7 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port)
* report whether the port is internal. * report whether the port is internal.
*/ */
if (chip->info->family == MV88E6XXX_FAMILY_6250) if (chip->info->family == MV88E6XXX_FAMILY_6250)
return port < chip->info->num_internal_phys; return mv88e6xxx_phy_is_internal(chip, port);
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg); err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
if (err) { if (err) {
...@@ -584,7 +584,7 @@ static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, ...@@ -584,7 +584,7 @@ static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
if (mv88e6xxx_phy_is_internal(chip->ds, port)) { if (mv88e6xxx_phy_is_internal(chip, port)) {
__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
} else { } else {
if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
...@@ -790,6 +790,8 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, ...@@ -790,6 +790,8 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
unsigned long *supported = config->supported_interfaces; unsigned long *supported = config->supported_interfaces;
bool is_6191x = bool is_6191x =
chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
bool is_6361 =
chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361;
mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
...@@ -804,13 +806,17 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, ...@@ -804,13 +806,17 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
/* 6191X supports >1G modes only on port 10 */ /* 6191X supports >1G modes only on port 10 */
if (!is_6191x || port == 10) { if (!is_6191x || port == 10) {
__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
config->mac_capabilities |= MAC_2500FD;
/* 6361 only supports up to 2500BaseX */
if (!is_6361) {
__set_bit(PHY_INTERFACE_MODE_5GBASER, supported); __set_bit(PHY_INTERFACE_MODE_5GBASER, supported);
__set_bit(PHY_INTERFACE_MODE_10GBASER, supported); __set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
config->mac_capabilities |= MAC_5000FD |
MAC_10000FD;
}
/* FIXME: USXGMII is not supported yet */ /* FIXME: USXGMII is not supported yet */
/* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */
config->mac_capabilities |= MAC_2500FD | MAC_5000FD |
MAC_10000FD;
} }
} }
...@@ -832,7 +838,7 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, ...@@ -832,7 +838,7 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
chip->info->ops->phylink_get_caps(chip, port, config); chip->info->ops->phylink_get_caps(chip, port, config);
mv88e6xxx_reg_unlock(chip); mv88e6xxx_reg_unlock(chip);
if (mv88e6xxx_phy_is_internal(ds, port)) { if (mv88e6xxx_phy_is_internal(chip, port)) {
__set_bit(PHY_INTERFACE_MODE_INTERNAL, __set_bit(PHY_INTERFACE_MODE_INTERNAL,
config->supported_interfaces); config->supported_interfaces);
/* Internal ports with no phy-mode need GMII for PHYLIB */ /* Internal ports with no phy-mode need GMII for PHYLIB */
...@@ -872,7 +878,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, ...@@ -872,7 +878,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) { if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(chip, port)) {
err = mv88e6xxx_port_config_interface(chip, port, err = mv88e6xxx_port_config_interface(chip, port,
state->interface); state->interface);
if (err && err != -EOPNOTSUPP) if (err && err != -EOPNOTSUPP)
...@@ -3334,7 +3340,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) ...@@ -3334,7 +3340,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
caps = pl_config.mac_capabilities; caps = pl_config.mac_capabilities;
if (chip->info->ops->port_max_speed_mode) if (chip->info->ops->port_max_speed_mode)
mode = chip->info->ops->port_max_speed_mode(port); mode = chip->info->ops->port_max_speed_mode(chip, port);
else else
mode = PHY_INTERFACE_MODE_NA; mode = PHY_INTERFACE_MODE_NA;
...@@ -6047,7 +6053,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -6047,7 +6053,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6191X", .name = "Marvell 88E6191X",
.num_databases = 4096, .num_databases = 4096,
.num_ports = 11, /* 10 + Z80 */ .num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9, .num_internal_phys = 8,
.internal_phys_offset = 1,
.max_vid = 8191, .max_vid = 8191,
.max_sid = 63, .max_sid = 63,
.port_base_addr = 0x0, .port_base_addr = 0x0,
...@@ -6070,7 +6077,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -6070,7 +6077,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6193X", .name = "Marvell 88E6193X",
.num_databases = 4096, .num_databases = 4096,
.num_ports = 11, /* 10 + Z80 */ .num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9, .num_internal_phys = 8,
.internal_phys_offset = 1,
.max_vid = 8191, .max_vid = 8191,
.max_sid = 63, .max_sid = 63,
.port_base_addr = 0x0, .port_base_addr = 0x0,
...@@ -6332,6 +6340,32 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -6332,6 +6340,32 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.ptp_support = true, .ptp_support = true,
.ops = &mv88e6352_ops, .ops = &mv88e6352_ops,
}, },
[MV88E6361] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6361,
.family = MV88E6XXX_FAMILY_6393,
.name = "Marvell 88E6361",
.num_databases = 4096,
.num_macs = 16384,
.num_ports = 11,
/* Ports 1, 2 and 8 are not routed */
.invalid_port_mask = BIT(1) | BIT(2) | BIT(8),
.num_internal_phys = 5,
.internal_phys_offset = 3,
.max_vid = 4095,
.max_sid = 63,
.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,
.ptp_support = true,
.ops = &mv88e6393x_ops,
},
[MV88E6390] = { [MV88E6390] = {
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
.family = MV88E6XXX_FAMILY_6390, .family = MV88E6XXX_FAMILY_6390,
...@@ -6389,7 +6423,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { ...@@ -6389,7 +6423,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.name = "Marvell 88E6393X", .name = "Marvell 88E6393X",
.num_databases = 4096, .num_databases = 4096,
.num_ports = 11, /* 10 + Z80 */ .num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9, .num_internal_phys = 8,
.internal_phys_offset = 1,
.max_vid = 8191, .max_vid = 8191,
.max_sid = 63, .max_sid = 63,
.port_base_addr = 0x0, .port_base_addr = 0x0,
......
...@@ -82,6 +82,7 @@ enum mv88e6xxx_model { ...@@ -82,6 +82,7 @@ enum mv88e6xxx_model {
MV88E6350, MV88E6350,
MV88E6351, MV88E6351,
MV88E6352, MV88E6352,
MV88E6361,
MV88E6390, MV88E6390,
MV88E6390X, MV88E6390X,
MV88E6393X, MV88E6393X,
...@@ -100,7 +101,7 @@ enum mv88e6xxx_family { ...@@ -100,7 +101,7 @@ enum mv88e6xxx_family {
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6393X */ MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6361 6393X */
}; };
/** /**
...@@ -167,6 +168,11 @@ struct mv88e6xxx_info { ...@@ -167,6 +168,11 @@ struct mv88e6xxx_info {
/* Supports PTP */ /* Supports PTP */
bool ptp_support; bool ptp_support;
/* Internal PHY start index. 0 means that internal PHYs range starts at
* port 0, 1 means internal PHYs range starts at port 1, etc
*/
unsigned int internal_phys_offset;
}; };
struct mv88e6xxx_atu_entry { struct mv88e6xxx_atu_entry {
...@@ -513,7 +519,8 @@ struct mv88e6xxx_ops { ...@@ -513,7 +519,8 @@ struct mv88e6xxx_ops {
int speed, int duplex); int speed, int duplex);
/* What interface mode should be used for maximum speed? */ /* What interface mode should be used for maximum speed? */
phy_interface_t (*port_max_speed_mode)(int port); phy_interface_t (*port_max_speed_mode)(struct mv88e6xxx_chip *chip,
int port);
int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port);
......
...@@ -1196,9 +1196,12 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip) ...@@ -1196,9 +1196,12 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip, int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip,
struct mii_bus *bus) struct mii_bus *bus)
{ {
int phy_start = chip->info->internal_phys_offset;
int phy_end = chip->info->internal_phys_offset +
chip->info->num_internal_phys;
int phy, irq; int phy, irq;
for (phy = 0; phy < chip->info->num_internal_phys; phy++) { for (phy = phy_start; phy < phy_end; phy++) {
irq = irq_find_mapping(chip->g2_irq.domain, phy); irq = irq_find_mapping(chip->g2_irq.domain, phy);
if (irq < 0) if (irq < 0)
return irq; return irq;
......
...@@ -342,7 +342,8 @@ int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -342,7 +342,8 @@ int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
duplex); duplex);
} }
phy_interface_t mv88e6341_port_max_speed_mode(int port) phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip,
int port)
{ {
if (port == 5) if (port == 5)
return PHY_INTERFACE_MODE_2500BASEX; return PHY_INTERFACE_MODE_2500BASEX;
...@@ -381,7 +382,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -381,7 +382,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
duplex); duplex);
} }
phy_interface_t mv88e6390_port_max_speed_mode(int port) phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip,
int port)
{ {
if (port == 9 || port == 10) if (port == 9 || port == 10)
return PHY_INTERFACE_MODE_2500BASEX; return PHY_INTERFACE_MODE_2500BASEX;
...@@ -403,7 +405,8 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -403,7 +405,8 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
duplex); duplex);
} }
phy_interface_t mv88e6390x_port_max_speed_mode(int port) phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip,
int port)
{ {
if (port == 9 || port == 10) if (port == 9 || port == 10)
return PHY_INTERFACE_MODE_XAUI; return PHY_INTERFACE_MODE_XAUI;
...@@ -421,6 +424,10 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -421,6 +424,10 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
u16 reg, ctrl; u16 reg, ctrl;
int err; int err;
if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 &&
speed > 2500)
return -EOPNOTSUPP;
if (speed == 200 && port != 0) if (speed == 200 && port != 0)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -500,12 +507,17 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -500,12 +507,17 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
return 0; return 0;
} }
phy_interface_t mv88e6393x_port_max_speed_mode(int port) 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_10GBASER;
if (port != 0 && port != 9 && port != 10)
return PHY_INTERFACE_MODE_NA; 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;
} }
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
......
...@@ -133,6 +133,7 @@ ...@@ -133,6 +133,7 @@
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6250 0x2500 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6250 0x2500
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6361 0x2610
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400
...@@ -359,10 +360,14 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, ...@@ -359,10 +360,14 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
int speed, int duplex); int speed, int duplex);
phy_interface_t mv88e6341_port_max_speed_mode(int port); phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip,
phy_interface_t mv88e6390_port_max_speed_mode(int port); int port);
phy_interface_t mv88e6390x_port_max_speed_mode(int port); phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip,
phy_interface_t mv88e6393x_port_max_speed_mode(int port); int port);
phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip,
int port);
phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip,
int port);
int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state); int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment