summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/mv88e6xxx/port.c
diff options
context:
space:
mode:
authorRasmus Villemoes <rasmus.villemoes@prevas.dk>2019-06-04 07:34:30 +0000
committerDavid S. Miller <davem@davemloft.net>2019-06-04 20:07:57 -0700
commitce91c45321e81c7ec1a41555c05a1fb14acfc076 (patch)
tree180e5b217c550223e76aace3c7e9a9e36ba5971f /drivers/net/dsa/mv88e6xxx/port.c
parenta528e5be6b5f8026eda029b03340dcfa23c70824 (diff)
net: dsa: mv88e6xxx: implement port_link_state for mv88e6250
The mv88e6250 has a rather different way of reporting the link, speed and duplex status. A simple difference is that the link bit is bit 12 rather than bit 11 of the port status register. It gets more complicated for speed and duplex, which do not have separate fields. Instead, there's a four-bit PortMode field, and decoding that depends on whether it's a phy or mii port. For the phy ports, only four of the 16 values have defined meaning; the rest are called "reserved", so returning {SPEED,DUPLEX}_UNKNOWN seems reasonable. For the mii ports, most possible values are documented (0x3 and 0x5 are reserved), but I'm unable to make sense of them all. Since the bits simply reflect the Px_MODE[3:0] configuration pins, just support the subset that I'm certain about. Support for other setups can be added later. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/port.c')
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index a41bca17cba1..a9a308051d7c 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -533,6 +533,71 @@ int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode)
return 0;
}
+int mv88e6250_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err)
+ return err;
+
+ if (port < 5) {
+ switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) {
+ case MV88E6250_PORT_STS_PORTMODE_PHY_10_HALF:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_100_HALF:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_10_FULL:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_FULL;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_PHY_100_FULL:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+ } else {
+ switch (reg & MV88E6250_PORT_STS_PORTMODE_MASK) {
+ case MV88E6250_PORT_STS_PORTMODE_MII_10_HALF:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_100_HALF:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_HALF;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_10_FULL:
+ state->speed = SPEED_10;
+ state->duplex = DUPLEX_FULL;
+ break;
+ case MV88E6250_PORT_STS_PORTMODE_MII_100_FULL:
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_FULL;
+ break;
+ default:
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ break;
+ }
+ }
+
+ state->link = !!(reg & MV88E6250_PORT_STS_LINK);
+ state->an_enabled = 1;
+ state->an_complete = state->link;
+
+ return 0;
+}
+
int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
struct phylink_link_state *state)
{