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

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
...@@ -10,6 +10,7 @@ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o ...@@ -10,6 +10,7 @@ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
mv88e6xxx-objs += phy.o mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
mv88e6xxx-objs += serdes.o mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o mv88e6xxx-objs += smi.o
...@@ -454,6 +454,12 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, ...@@ -454,6 +454,12 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
goto restore_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) { if (chip->info->ops->port_set_cmode) {
err = chip->info->ops->port_set_cmode(chip, port, mode); err = chip->info->ops->port_set_cmode(chip, port, mode);
if (err && err != -EOPNOTSUPP) if (err && err != -EOPNOTSUPP)
...@@ -2317,60 +2323,6 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) ...@@ -2317,60 +2323,6 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip)
return mv88e6xxx_g1_stats_clear(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. */ /* Check if the errata has already been applied. */
static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
{ {
...@@ -2379,7 +2331,7 @@ 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; u16 val;
for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 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) { if (err) {
dev_err(chip->dev, dev_err(chip->dev,
"Error reading hidden register: %d\n", err); "Error reading hidden register: %d\n", err);
...@@ -2412,7 +2364,7 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) ...@@ -2412,7 +2364,7 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
} }
for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { 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) if (err)
return err; return err;
} }
...@@ -2967,6 +2919,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { ...@@ -2967,6 +2919,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_link_state = mv88e6352_port_link_state, .port_link_state = mv88e6352_port_link_state,
.port_get_cmode = mv88e6352_port_get_cmode, .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, .port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6390_g1_stats_snapshot, .stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram, .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
...@@ -2981,7 +2935,10 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { ...@@ -2981,7 +2935,10 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.reset = mv88e6352_g1_reset, .reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .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, .gpio_ops = &mv88e6352_gpio_ops,
.phylink_validate = mv88e6341_phylink_validate, .phylink_validate = mv88e6341_phylink_validate,
}; };
...@@ -3309,6 +3266,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { ...@@ -3309,6 +3266,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free, .serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
...@@ -3354,9 +3312,10 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { ...@@ -3354,9 +3312,10 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.rmu_disable = mv88e6390_g1_rmu_disable, .rmu_disable = mv88e6390_g1_rmu_disable,
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup, .serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_free = mv88e6390x_serdes_irq_free, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.phylink_validate = mv88e6390x_phylink_validate, .phylink_validate = mv88e6390x_phylink_validate,
}; };
...@@ -3401,6 +3360,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { ...@@ -3401,6 +3360,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free, .serdes_irq_free = mv88e6390_serdes_irq_free,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
...@@ -3537,6 +3497,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { ...@@ -3537,6 +3497,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free, .serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
...@@ -3657,6 +3618,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { ...@@ -3657,6 +3618,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_link_state = mv88e6352_port_link_state, .port_link_state = mv88e6352_port_link_state,
.port_get_cmode = mv88e6352_port_get_cmode, .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, .port_setup_message_port = mv88e6xxx_setup_message_port,
.stats_snapshot = mv88e6390_g1_stats_snapshot, .stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram, .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
...@@ -3671,7 +3634,10 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { ...@@ -3671,7 +3634,10 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.reset = mv88e6352_g1_reset, .reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .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, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops, .ptp_ops = &mv88e6352_ptp_ops,
...@@ -3854,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { ...@@ -3854,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free, .serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
...@@ -3903,9 +3870,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { ...@@ -3903,9 +3870,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.rmu_disable = mv88e6390_g1_rmu_disable, .rmu_disable = mv88e6390_g1_rmu_disable,
.vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power, .serdes_power = mv88e6390_serdes_power,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup, .serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_free = mv88e6390x_serdes_irq_free, .serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops, .gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops, .avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops, .ptp_ops = &mv88e6352_ptp_ops,
......
...@@ -400,6 +400,7 @@ struct mv88e6xxx_ops { ...@@ -400,6 +400,7 @@ struct mv88e6xxx_ops {
/* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc. /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc.
* Some chips allow this to be configured on specific ports. * 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, int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode); phy_interface_t mode);
int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode); int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
...@@ -443,6 +444,9 @@ struct mv88e6xxx_ops { ...@@ -443,6 +444,9 @@ struct mv88e6xxx_ops {
/* Power on/off a SERDES interface */ /* Power on/off a SERDES interface */
int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on); 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 */ /* SERDES interrupt handling */
int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port); int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port); void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);
......
...@@ -392,17 +392,14 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port) ...@@ -392,17 +392,14 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
return PHY_INTERFACE_MODE_NA; 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) phy_interface_t mode)
{ {
int lane; u8 lane;
u16 cmode; u16 cmode;
u16 reg; u16 reg;
int err; int err;
if (port != 9 && port != 10)
return -EOPNOTSUPP;
/* Default to a slow mode, so freeing up SERDES interfaces for /* Default to a slow mode, so freeing up SERDES interfaces for
* other ports which might use them for SFPs. * other ports which might use them for SFPs.
*/ */
...@@ -411,7 +408,7 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, ...@@ -411,7 +408,7 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
switch (mode) { switch (mode) {
case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_1000BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X; cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
break; break;
case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_SGMII:
cmode = MV88E6XXX_PORT_STS_CMODE_SGMII; cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
...@@ -434,18 +431,18 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, ...@@ -434,18 +431,18 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
if (cmode == chip->ports[port].cmode) if (cmode == chip->ports[port].cmode)
return 0; return 0;
lane = mv88e6390x_serdes_get_lane(chip, port); err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (lane < 0 && lane != -ENODEV) if (err && err != -ENODEV)
return lane; return err;
if (lane >= 0) { if (err != -ENODEV) {
if (chip->ports[port].serdes_irq) { if (chip->ports[port].serdes_irq) {
err = mv88e6390_serdes_irq_disable(chip, port, lane); err = mv88e6390_serdes_irq_disable(chip, port, lane);
if (err) if (err)
return err; return err;
} }
err = mv88e6390x_serdes_power(chip, port, false); err = mv88e6390_serdes_power(chip, port, false);
if (err) if (err)
return err; return err;
} }
...@@ -466,11 +463,11 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, ...@@ -466,11 +463,11 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
chip->ports[port].cmode = cmode; chip->ports[port].cmode = cmode;
lane = mv88e6390x_serdes_get_lane(chip, port); err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (lane < 0) if (err)
return lane; return err;
err = mv88e6390x_serdes_power(chip, port, true); err = mv88e6390_serdes_power(chip, port, true);
if (err) if (err)
return err; return err;
...@@ -484,9 +481,65 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, ...@@ -484,9 +481,65 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
return 0; 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, int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode) 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) { switch (mode) {
case PHY_INTERFACE_MODE_NA: case PHY_INTERFACE_MODE_NA:
return 0; return 0;
...@@ -498,7 +551,7 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, ...@@ -498,7 +551,7 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
break; 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) 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, ...@@ -618,7 +671,7 @@ int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
else else
state->interface = PHY_INTERFACE_MODE_RGMII; state->interface = PHY_INTERFACE_MODE_RGMII;
break; break;
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
state->interface = PHY_INTERFACE_MODE_1000BASEX; state->interface = PHY_INTERFACE_MODE_1000BASEX;
break; break;
case MV88E6XXX_PORT_STS_CMODE_SGMII: case MV88E6XXX_PORT_STS_CMODE_SGMII:
......
...@@ -43,8 +43,8 @@ ...@@ -43,8 +43,8 @@
#define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010 #define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010
#define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f #define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f
#define MV88E6XXX_PORT_STS_CMODE_RGMII 0x0007 #define MV88E6XXX_PORT_STS_CMODE_RGMII 0x0007
#define MV88E6XXX_PORT_STS_CMODE_100BASE_X 0x0008 #define MV88E6XXX_PORT_STS_CMODE_100BASEX 0x0008
#define MV88E6XXX_PORT_STS_CMODE_1000BASE_X 0x0009 #define MV88E6XXX_PORT_STS_CMODE_1000BASEX 0x0009
#define MV88E6XXX_PORT_STS_CMODE_SGMII 0x000a #define MV88E6XXX_PORT_STS_CMODE_SGMII 0x000a
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b #define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c #define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
...@@ -261,14 +261,16 @@ ...@@ -261,14 +261,16 @@
#define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 #define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19
/* Offset 0x1a: Magic undocumented errata register */ /* Offset 0x1a: Magic undocumented errata register */
#define PORT_RESERVED_1A 0x1a #define MV88E6XXX_PORT_RESERVED_1A 0x1a
#define PORT_RESERVED_1A_BUSY BIT(15) #define MV88E6XXX_PORT_RESERVED_1A_BUSY 0x8000
#define PORT_RESERVED_1A_WRITE BIT(14) #define MV88E6XXX_PORT_RESERVED_1A_WRITE 0x4000
#define PORT_RESERVED_1A_READ 0 #define MV88E6XXX_PORT_RESERVED_1A_READ 0x0000
#define PORT_RESERVED_1A_PORT_SHIFT 5 #define MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT 5
#define PORT_RESERVED_1A_BLOCK (0xf << 10) #define MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT 10
#define PORT_RESERVED_1A_CTRL_PORT 4 #define MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT 0x04
#define PORT_RESERVED_1A_DATA_PORT 5 #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, int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
u16 *val); u16 *val);
...@@ -334,6 +336,9 @@ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, ...@@ -334,6 +336,9 @@ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
u8 out); u8 out);
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in, int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
u8 out); 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, int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode); phy_interface_t mode);
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, 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, ...@@ -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_learn_limit(struct mv88e6xxx_chip *chip, int port);
int mv88e6xxx_port_disable_pri_override(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 */ #endif /* _MV88E6XXX_PORT_H */
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Hidden Registers support
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2019 Andrew Lunn <andrew@lunn.ch>
*/
#include <linux/bitfield.h>
#include "chip.h"
#include "port.h"
/* The mv88e6390 and mv88e6341 have some hidden registers used for debug and
* development. The errata also makes use of them.
*/
int mv88e6xxx_port_hidden_write(struct mv88e6xxx_chip *chip, int block,
int port, int reg, u16 val)
{
u16 ctrl;
int err;
err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
MV88E6XXX_PORT_RESERVED_1A, val);
if (err)
return err;
ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
MV88E6XXX_PORT_RESERVED_1A_WRITE |
block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
reg;
return mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
MV88E6XXX_PORT_RESERVED_1A, ctrl);
}
int mv88e6xxx_port_hidden_wait(struct mv88e6xxx_chip *chip)
{
int bit = __bf_shf(MV88E6XXX_PORT_RESERVED_1A_BUSY);
return mv88e6xxx_wait_bit(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
MV88E6XXX_PORT_RESERVED_1A, bit, 0);
}
int mv88e6xxx_port_hidden_read(struct mv88e6xxx_chip *chip, int block, int port,
int reg, u16 *val)
{
u16 ctrl;
int err;
ctrl = MV88E6XXX_PORT_RESERVED_1A_BUSY |
MV88E6XXX_PORT_RESERVED_1A_READ |
block << MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT |
port << MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT |
reg;
err = mv88e6xxx_port_write(chip, MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT,
MV88E6XXX_PORT_RESERVED_1A, ctrl);
if (err)
return err;
err = mv88e6xxx_port_hidden_wait(chip);
if (err)
return err;
return mv88e6xxx_port_read(chip, MV88E6XXX_PORT_RESERVED_1A_DATA_PORT,
MV88E6XXX_PORT_RESERVED_1A, val);
}
...@@ -73,8 +73,8 @@ static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) ...@@ -73,8 +73,8 @@ static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
{ {
u8 cmode = chip->ports[port].cmode; u8 cmode = chip->ports[port].cmode;
if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) || if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) || (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
(cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
return true; return true;
...@@ -286,36 +286,52 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) ...@@ -286,36 +286,52 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
chip->ports[port].serdes_irq = 0; chip->ports[port].serdes_irq = 0;
} }
/* Return the SERDES lane address a port is using. Only Ports 9 and 10 int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
* have SERDES lanes. Returns -ENODEV if a port does not have a lane. {
*/ u8 cmode = chip->ports[port].cmode;
static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
if (port != 5)
return -ENODEV;
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
*lane = MV88E6341_PORT5_LANE;
return 0;
}
return -ENODEV;
}
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
{ {
u8 cmode = chip->ports[port].cmode; u8 cmode = chip->ports[port].cmode;
switch (port) { switch (port) {
case 9: case 9:
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
return MV88E6390_PORT9_LANE0; *lane = MV88E6390_PORT9_LANE0;
return -ENODEV; return 0;
}
break;
case 10: case 10:
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
return MV88E6390_PORT10_LANE0; *lane = MV88E6390_PORT10_LANE0;
return -ENODEV; return 0;
}
break;
default: default:
return -ENODEV; break;
} }
return -ENODEV;
} }
/* Return the SERDES lane address a port is using. Ports 9 and 10 can int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
* use multiple lanes. If so, return the first lane the port uses.
* Returns -ENODEV if a port does not have a lane.
*/
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
{ {
u8 cmode_port9, cmode_port10, cmode_port; u8 cmode_port9, cmode_port10, cmode_port;
...@@ -325,74 +341,98 @@ int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) ...@@ -325,74 +341,98 @@ int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
switch (port) { switch (port) {
case 2: case 2:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT9_LANE1; *lane = MV88E6390_PORT9_LANE1;
return -ENODEV; return 0;
}
}
break;
case 3: case 3:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT9_LANE2; *lane = MV88E6390_PORT9_LANE2;
return -ENODEV; return 0;
}
}
break;
case 4: case 4:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT9_LANE3; *lane = MV88E6390_PORT9_LANE3;
return -ENODEV; return 0;
}
}
break;
case 5: case 5:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT10_LANE1; *lane = MV88E6390_PORT10_LANE1;
return -ENODEV; return 0;
}
}
break;
case 6: case 6:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT10_LANE2; *lane = MV88E6390_PORT10_LANE2;
return -ENODEV; return 0;
}
}
break;
case 7: case 7:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
return MV88E6390_PORT10_LANE3; *lane = MV88E6390_PORT10_LANE3;
return -ENODEV; return 0;
}
}
break;
case 9: case 9:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
return MV88E6390_PORT9_LANE0; *lane = MV88E6390_PORT9_LANE0;
return -ENODEV; return 0;
}
break;
case 10: case 10:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X || if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
return MV88E6390_PORT10_LANE0; *lane = MV88E6390_PORT10_LANE0;
return -ENODEV; return 0;
}
break;
default: default:
return -ENODEV; break;
} }
return -ENODEV;
} }
/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */ /* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane, static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
bool on) bool on)
{ {
u16 val, new_val; u16 val, new_val;
...@@ -419,7 +459,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane, ...@@ -419,7 +459,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
} }
/* Set the power on/off for SGMII and 1000Base-X */ /* Set the power on/off for SGMII and 1000Base-X */
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane, static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
bool on) bool on)
{ {
u16 val, new_val; u16 val, new_val;
...@@ -444,14 +484,22 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane, ...@@ -444,14 +484,22 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
return err; return err;
} }
static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port, int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
int lane, bool on)
{ {
u8 cmode = chip->ports[port].cmode; u8 cmode = chip->ports[port].cmode;
u8 lane;
int err;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err == -ENODEV)
err = 0;
return err;
}
switch (cmode) { switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII: case MV88E6XXX_PORT_STS_CMODE_SGMII:
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
case MV88E6XXX_PORT_STS_CMODE_2500BASEX: case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
return mv88e6390_serdes_power_sgmii(chip, lane, on); return mv88e6390_serdes_power_sgmii(chip, lane, on);
case MV88E6XXX_PORT_STS_CMODE_XAUI: case MV88E6XXX_PORT_STS_CMODE_XAUI:
...@@ -462,52 +510,14 @@ static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port, ...@@ -462,52 +510,14 @@ static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
return 0; return 0;
} }
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
int lane;
lane = mv88e6390_serdes_get_lane(chip, port);
if (lane == -ENODEV)
return 0;
if (lane < 0)
return lane;
switch (port) {
case 9 ... 10:
return mv88e6390_serdes_power_lane(chip, port, lane, on);
}
return 0;
}
int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
int lane;
lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane == -ENODEV)
return 0;
if (lane < 0)
return lane;
switch (port) {
case 2 ... 4:
case 5 ... 7:
case 9 ... 10:
return mv88e6390_serdes_power_lane(chip, port, lane, on);
}
return 0;
}
static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
int port, int lane) int port, u8 lane)
{ {
u8 cmode = chip->ports[port].cmode;
struct dsa_switch *ds = chip->ds; struct dsa_switch *ds = chip->ds;
int duplex = DUPLEX_UNKNOWN; int duplex = DUPLEX_UNKNOWN;
int speed = SPEED_UNKNOWN; int speed = SPEED_UNKNOWN;
phy_interface_t mode;
int link, err; int link, err;
u16 status; u16 status;
...@@ -527,6 +537,9 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, ...@@ -527,6 +537,9 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
speed = SPEED_2500;
else
speed = SPEED_1000; speed = SPEED_1000;
break; break;
case MV88E6390_SGMII_PHY_STATUS_SPEED_100: case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
...@@ -541,8 +554,22 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, ...@@ -541,8 +554,22 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
} }
} }
switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII:
mode = PHY_INTERFACE_MODE_SGMII;
break;
case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
mode = PHY_INTERFACE_MODE_1000BASEX;
break;
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
mode = PHY_INTERFACE_MODE_2500BASEX;
break;
default:
mode = PHY_INTERFACE_MODE_NA;
}
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex,
PAUSE_OFF, PHY_INTERFACE_MODE_NA); PAUSE_OFF, mode);
if (err) if (err)
dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n", dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
err); err);
...@@ -551,7 +578,7 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, ...@@ -551,7 +578,7 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
} }
static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
int lane) u8 lane)
{ {
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_INT_ENABLE, MV88E6390_SGMII_INT_ENABLE,
...@@ -560,21 +587,21 @@ static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, ...@@ -560,21 +587,21 @@ static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
} }
static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip, static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
int lane) u8 lane)
{ {
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_INT_ENABLE, 0); MV88E6390_SGMII_INT_ENABLE, 0);
} }
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
int lane) u8 lane)
{ {
u8 cmode = chip->ports[port].cmode; u8 cmode = chip->ports[port].cmode;
int err = 0; int err = 0;
switch (cmode) { switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII: case MV88E6XXX_PORT_STS_CMODE_SGMII:
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
case MV88E6XXX_PORT_STS_CMODE_2500BASEX: case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
err = mv88e6390_serdes_irq_enable_sgmii(chip, lane); err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
} }
...@@ -583,14 +610,14 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, ...@@ -583,14 +610,14 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
} }
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port, int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
int lane) u8 lane)
{ {
u8 cmode = chip->ports[port].cmode; u8 cmode = chip->ports[port].cmode;
int err = 0; int err = 0;
switch (cmode) { switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII: case MV88E6XXX_PORT_STS_CMODE_SGMII:
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
case MV88E6XXX_PORT_STS_CMODE_2500BASEX: case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
err = mv88e6390_serdes_irq_disable_sgmii(chip, lane); err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
} }
...@@ -599,7 +626,7 @@ int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port, ...@@ -599,7 +626,7 @@ int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
} }
static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip, static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
int lane, u16 *status) u8 lane, u16 *status)
{ {
int err; int err;
...@@ -616,16 +643,16 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id) ...@@ -616,16 +643,16 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
u8 cmode = port->cmode; u8 cmode = port->cmode;
u16 status; u16 status;
int lane;
int err; int err;
u8 lane;
lane = mv88e6390x_serdes_get_lane(chip, port->port); mv88e6xxx_serdes_get_lane(chip, port->port, &lane);
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
switch (cmode) { switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII: case MV88E6XXX_PORT_STS_CMODE_SGMII:
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X: case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
case MV88E6XXX_PORT_STS_CMODE_2500BASEX: case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status); err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
if (err) if (err)
...@@ -642,18 +669,17 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id) ...@@ -642,18 +669,17 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
return ret; return ret;
} }
int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
{ {
int lane;
int err; int err;
u8 lane;
lane = mv88e6390x_serdes_get_lane(chip, port); err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (lane == -ENODEV) if (err == -ENODEV)
return 0; err = 0;
return err;
if (lane < 0) }
return lane;
chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain, chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
port); port);
...@@ -682,23 +708,18 @@ int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) ...@@ -682,23 +708,18 @@ int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
return mv88e6390_serdes_irq_enable(chip, port, lane); return mv88e6390_serdes_irq_enable(chip, port, lane);
} }
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port) void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{
if (port < 9)
return 0;
return mv88e6390x_serdes_irq_setup(chip, port);
}
void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{ {
int lane = mv88e6390x_serdes_get_lane(chip, port); int err;
u8 lane;
if (lane == -ENODEV)
return;
if (lane < 0) err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err != -ENODEV)
dev_err(chip->dev, "Unable to free SERDES irq: %d\n",
err);
return; return;
}
mv88e6390_serdes_irq_disable(chip, port, lane); mv88e6390_serdes_irq_disable(chip, port, lane);
...@@ -711,27 +732,3 @@ void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port) ...@@ -711,27 +732,3 @@ void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
chip->ports[port].serdes_irq = 0; chip->ports[port].serdes_irq = 0;
} }
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{
if (port < 9)
return;
mv88e6390x_serdes_irq_free(chip, port);
}
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
u8 cmode = chip->ports[port].cmode;
if (port != 5)
return 0;
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
return mv88e6390_serdes_power_sgmii(chip, MV88E6341_ADDR_SERDES,
on);
return 0;
}
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#define MV88E6352_SERDES_INT_STATUS 0x13 #define MV88E6352_SERDES_INT_STATUS 0x13
#define MV88E6341_ADDR_SERDES 0x15 #define MV88E6341_PORT5_LANE 0x15
#define MV88E6390_PORT9_LANE0 0x09 #define MV88E6390_PORT9_LANE0 0x09
#define MV88E6390_PORT9_LANE1 0x12 #define MV88E6390_PORT9_LANE1 0x12
...@@ -74,24 +74,35 @@ ...@@ -74,24 +74,35 @@
#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11) #define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10) #define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); /* Put the SERDES lane address a port is using into *lane. If a port has
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); * multiple lanes, should put the first lane the port is using. If a port does
* not have a lane, return -ENODEV.
*/
static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
int port, u8 *lane)
{
if (!chip->info->ops->serdes_get_lane)
return -EOPNOTSUPP;
return chip->info->ops->serdes_get_lane(chip, port, lane);
}
int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on); int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port); int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port); void mv88e6390_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data); int port, uint8_t *data);
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data); uint64_t *data);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
int lane); u8 lane);
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port, int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
int lane); u8 lane);
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port); int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port); void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
......
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