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);
}
This diff is collapsed.
...@@ -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