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: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
0e5c9ab32c
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -484,9 +481,21 @@ 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;
|
||||
|
@ -498,7 +507,51 @@ 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 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, ®);
|
||||
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;
|
||||
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 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,
|
|||
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:
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
#define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010
|
||||
#define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f
|
||||
#define MV88E6XXX_PORT_STS_CMODE_RGMII 0x0007
|
||||
#define MV88E6XXX_PORT_STS_CMODE_100BASE_X 0x0008
|
||||
#define MV88E6XXX_PORT_STS_CMODE_1000BASE_X 0x0009
|
||||
#define MV88E6XXX_PORT_STS_CMODE_100BASEX 0x0008
|
||||
#define MV88E6XXX_PORT_STS_CMODE_1000BASEX 0x0009
|
||||
#define MV88E6XXX_PORT_STS_CMODE_SGMII 0x000a
|
||||
#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
|
||||
#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
|
||||
|
@ -261,14 +261,16 @@
|
|||
#define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19
|
||||
|
||||
/* Offset 0x1a: Magic undocumented errata register */
|
||||
#define PORT_RESERVED_1A 0x1a
|
||||
#define PORT_RESERVED_1A_BUSY BIT(15)
|
||||
#define PORT_RESERVED_1A_WRITE BIT(14)
|
||||
#define PORT_RESERVED_1A_READ 0
|
||||
#define PORT_RESERVED_1A_PORT_SHIFT 5
|
||||
#define PORT_RESERVED_1A_BLOCK (0xf << 10)
|
||||
#define PORT_RESERVED_1A_CTRL_PORT 4
|
||||
#define PORT_RESERVED_1A_DATA_PORT 5
|
||||
#define MV88E6XXX_PORT_RESERVED_1A 0x1a
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_BUSY 0x8000
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_WRITE 0x4000
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_READ 0x0000
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_PORT_SHIFT 5
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_BLOCK_SHIFT 10
|
||||
#define MV88E6XXX_PORT_RESERVED_1A_CTRL_PORT 0x04
|
||||
#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,
|
||||
u16 *val);
|
||||
|
@ -334,6 +336,9 @@ int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
|||
u8 out);
|
||||
int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
|
||||
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,
|
||||
phy_interface_t mode);
|
||||
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,
|
|||
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_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 */
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// 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)
|
|||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASE_X) ||
|
||||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) ||
|
||||
if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) ||
|
||||
(cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) ||
|
||||
(cmode == MV88E6XXX_PORT_STS_CMODE_SGMII))
|
||||
return true;
|
||||
|
||||
|
@ -286,36 +286,52 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
|
|||
chip->ports[port].serdes_irq = 0;
|
||||
}
|
||||
|
||||
/* Return the SERDES lane address a port is using. Only Ports 9 and 10
|
||||
* have SERDES lanes. Returns -ENODEV if a port does not have a lane.
|
||||
*/
|
||||
static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
|
||||
int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
|
||||
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;
|
||||
|
||||
switch (port) {
|
||||
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_2500BASEX)
|
||||
return MV88E6390_PORT9_LANE0;
|
||||
return -ENODEV;
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
|
||||
*lane = MV88E6390_PORT9_LANE0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
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_2500BASEX)
|
||||
return MV88E6390_PORT10_LANE0;
|
||||
return -ENODEV;
|
||||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
|
||||
*lane = MV88E6390_PORT10_LANE0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Return the SERDES lane address a port is using. Ports 9 and 10 can
|
||||
* 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)
|
||||
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
|
||||
{
|
||||
u8 cmode_port9, cmode_port10, cmode_port;
|
||||
|
||||
|
@ -325,74 +341,98 @@ int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
|
|||
|
||||
switch (port) {
|
||||
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_2500BASEX)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE1;
|
||||
return -ENODEV;
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT9_LANE1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE2;
|
||||
return -ENODEV;
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT9_LANE2;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT9_LANE3;
|
||||
return -ENODEV;
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT9_LANE3;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE1;
|
||||
return -ENODEV;
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT10_LANE1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE2;
|
||||
return -ENODEV;
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT10_LANE2;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
|
||||
return MV88E6390_PORT10_LANE3;
|
||||
return -ENODEV;
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) {
|
||||
*lane = MV88E6390_PORT10_LANE3;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
return MV88E6390_PORT9_LANE0;
|
||||
return -ENODEV;
|
||||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
*lane = MV88E6390_PORT9_LANE0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
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_2500BASEX ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
|
||||
return MV88E6390_PORT10_LANE0;
|
||||
return -ENODEV;
|
||||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
|
||||
*lane = MV88E6390_PORT10_LANE0;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
u16 val, new_val;
|
||||
|
@ -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 */
|
||||
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)
|
||||
{
|
||||
u16 val, new_val;
|
||||
|
@ -444,14 +484,22 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane, bool on)
|
||||
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
|
||||
{
|
||||
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) {
|
||||
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:
|
||||
return mv88e6390_serdes_power_sgmii(chip, lane, on);
|
||||
case MV88E6XXX_PORT_STS_CMODE_XAUI:
|
||||
|
@ -462,52 +510,14 @@ static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
|
|||
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,
|
||||
int port, int lane)
|
||||
int port, u8 lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
struct dsa_switch *ds = chip->ds;
|
||||
int duplex = DUPLEX_UNKNOWN;
|
||||
int speed = SPEED_UNKNOWN;
|
||||
phy_interface_t mode;
|
||||
int link, err;
|
||||
u16 status;
|
||||
|
||||
|
@ -527,7 +537,10 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
|
|||
|
||||
switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
|
||||
case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
|
||||
speed = SPEED_1000;
|
||||
if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
|
||||
speed = SPEED_2500;
|
||||
else
|
||||
speed = SPEED_1000;
|
||||
break;
|
||||
case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
|
||||
speed = SPEED_100;
|
||||
|
@ -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,
|
||||
PAUSE_OFF, PHY_INTERFACE_MODE_NA);
|
||||
PAUSE_OFF, mode);
|
||||
if (err)
|
||||
dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n",
|
||||
err);
|
||||
|
@ -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,
|
||||
int lane)
|
||||
u8 lane)
|
||||
{
|
||||
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_INT_ENABLE,
|
||||
|
@ -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,
|
||||
int lane)
|
||||
u8 lane)
|
||||
{
|
||||
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
|
||||
MV88E6390_SGMII_INT_ENABLE, 0);
|
||||
}
|
||||
|
||||
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
|
||||
int lane)
|
||||
u8 lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
int err = 0;
|
||||
|
||||
switch (cmode) {
|
||||
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:
|
||||
err = mv88e6390_serdes_irq_enable_sgmii(chip, lane);
|
||||
}
|
||||
|
@ -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 lane)
|
||||
u8 lane)
|
||||
{
|
||||
u8 cmode = chip->ports[port].cmode;
|
||||
int err = 0;
|
||||
|
||||
switch (cmode) {
|
||||
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:
|
||||
err = mv88e6390_serdes_irq_disable_sgmii(chip, lane);
|
||||
}
|
||||
|
@ -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,
|
||||
int lane, u16 *status)
|
||||
u8 lane, u16 *status)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -616,16 +643,16 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
|
|||
irqreturn_t ret = IRQ_NONE;
|
||||
u8 cmode = port->cmode;
|
||||
u16 status;
|
||||
int lane;
|
||||
int err;
|
||||
u8 lane;
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port->port);
|
||||
mv88e6xxx_serdes_get_lane(chip, port->port, &lane);
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
switch (cmode) {
|
||||
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:
|
||||
err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status);
|
||||
if (err)
|
||||
|
@ -642,18 +669,17 @@ out:
|
|||
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;
|
||||
u8 lane;
|
||||
|
||||
lane = mv88e6390x_serdes_get_lane(chip, port);
|
||||
|
||||
if (lane == -ENODEV)
|
||||
return 0;
|
||||
|
||||
if (lane < 0)
|
||||
return lane;
|
||||
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
|
||||
if (err) {
|
||||
if (err == -ENODEV)
|
||||
err = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
|
||||
port);
|
||||
|
@ -682,23 +708,18 @@ int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
|
|||
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;
|
||||
int err;
|
||||
u8 lane;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mv88e6390_serdes_irq_disable(chip, port, lane);
|
||||
|
||||
|
@ -711,27 +732,3 @@ void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
|
|||
|
||||
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 @@
|
|||
#define MV88E6352_SERDES_INT_STATUS 0x13
|
||||
|
||||
|
||||
#define MV88E6341_ADDR_SERDES 0x15
|
||||
#define MV88E6341_PORT5_LANE 0x15
|
||||
|
||||
#define MV88E6390_PORT9_LANE0 0x09
|
||||
#define MV88E6390_PORT9_LANE1 0x12
|
||||
|
@ -74,24 +74,35 @@
|
|||
#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
|
||||
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
|
||||
|
||||
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
|
||||
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
|
||||
/* Put the SERDES lane address a port is using into *lane. If a port has
|
||||
* 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 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);
|
||||
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_strings(struct mv88e6xxx_chip *chip,
|
||||
int port, uint8_t *data);
|
||||
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
|
||||
uint64_t *data);
|
||||
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 lane);
|
||||
u8 lane);
|
||||
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
|
||||
void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче