Skip to content

Commit

Permalink
Merge branch 'net-dsa-mv88e6xxx-Peridot-Topaz-SERDES-changes'
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 28, 2019
2 parents e93b4f0 + 7a3007d commit 0e5c9ab
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 264 deletions.
1 change: 1 addition & 0 deletions drivers/net/dsa/mv88e6xxx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2_scratch.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
mv88e6xxx-objs += port_hidden.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
mv88e6xxx-objs += serdes.o
mv88e6xxx-objs += smi.o
96 changes: 32 additions & 64 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,12 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int 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) {
err = chip->info->ops->port_set_cmode(chip, port, mode);
if (err && err != -EOPNOTSUPP)
Expand Down Expand Up @@ -2317,60 +2323,6 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *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. */
static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
{
Expand All @@ -2379,7 +2331,7 @@ static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip)
u16 val;

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) {
dev_err(chip->dev,
"Error reading hidden register: %d\n", err);
Expand Down Expand Up @@ -2412,7 +2364,7 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip)
}

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)
return err;
}
Expand Down Expand Up @@ -2967,6 +2919,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_link_state = mv88e6352_port_link_state,
.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,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand All @@ -2981,7 +2935,10 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.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,
.phylink_validate = mv88e6341_phylink_validate,
};
Expand Down Expand Up @@ -3309,6 +3266,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
Expand Down Expand Up @@ -3354,9 +3312,10 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.rmu_disable = mv88e6390_g1_rmu_disable,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
.serdes_irq_free = mv88e6390x_serdes_irq_free,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
.phylink_validate = mv88e6390x_phylink_validate,
};
Expand Down Expand Up @@ -3401,6 +3360,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.avb_ops = &mv88e6390_avb_ops,
Expand Down Expand Up @@ -3537,6 +3497,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
Expand Down Expand Up @@ -3657,6 +3618,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
.port_link_state = mv88e6352_port_link_state,
.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,
.stats_snapshot = mv88e6390_g1_stats_snapshot,
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
Expand All @@ -3671,7 +3634,10 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.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,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
Expand Down Expand Up @@ -3854,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
Expand Down Expand Up @@ -3903,9 +3870,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.rmu_disable = mv88e6390_g1_rmu_disable,
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
.serdes_irq_free = mv88e6390x_serdes_irq_free,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
.ptp_ops = &mv88e6352_ptp_ops,
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/dsa/mv88e6xxx/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ struct mv88e6xxx_ops {
/* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc.
* 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,
phy_interface_t mode);
int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
Expand Down Expand Up @@ -443,6 +444,9 @@ struct mv88e6xxx_ops {
/* Power on/off a SERDES interface */
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 */
int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);
Expand Down
89 changes: 71 additions & 18 deletions drivers/net/dsa/mv88e6xxx/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,17 +392,14 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
return PHY_INTERFACE_MODE_NA;
}

int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
{
int lane;
u8 lane;
u16 cmode;
u16 reg;
int err;

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

/* Default to a slow mode, so freeing up SERDES interfaces for
* other ports which might use them for SFPs.
*/
Expand All @@ -411,7 +408,7 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,

switch (mode) {
case PHY_INTERFACE_MODE_1000BASEX:
cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
cmode = MV88E6XXX_PORT_STS_CMODE_1000BASEX;
break;
case PHY_INTERFACE_MODE_SGMII:
cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
Expand All @@ -434,18 +431,18 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
if (cmode == chip->ports[port].cmode)
return 0;

lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane < 0 && lane != -ENODEV)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err && err != -ENODEV)
return err;

if (lane >= 0) {
if (err != -ENODEV) {
if (chip->ports[port].serdes_irq) {
err = mv88e6390_serdes_irq_disable(chip, port, lane);
if (err)
return err;
}

err = mv88e6390x_serdes_power(chip, port, false);
err = mv88e6390_serdes_power(chip, port, false);
if (err)
return err;
}
Expand All @@ -466,11 +463,11 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,

chip->ports[port].cmode = cmode;

lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane < 0)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err)
return err;

err = mv88e6390x_serdes_power(chip, port, true);
err = mv88e6390_serdes_power(chip, port, true);
if (err)
return err;

Expand All @@ -484,9 +481,65 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
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,
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) {
case PHY_INTERFACE_MODE_NA:
return 0;
Expand All @@ -498,7 +551,7 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
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)
Expand Down Expand Up @@ -618,7 +671,7 @@ int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
else
state->interface = PHY_INTERFACE_MODE_RGMII;
break;
case MV88E6XXX_PORT_STS_CMODE_1000BASE_X:
case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
state->interface = PHY_INTERFACE_MODE_1000BASEX;
break;
case MV88E6XXX_PORT_STS_CMODE_SGMII:
Expand Down
Loading

0 comments on commit 0e5c9ab

Please sign in to comment.