Skip to content

Commit 74b95b0

Browse files
committed
Merge branch 'mv88e6xxx-fixes'
Marek Behún says: ==================== mv88e6xxx fixes (mainly 88E6393X family) sending v2 of these fixes. Original cover letter: So I managed to discovered how to fix inband AN for 2500base-x mode on 88E6393x (Amethyst) family. This series fixes application of erratum 4.8, adds fix for erratum 5.2, adds support for completely disablign SerDes receiver / transmitter, fixes inband AN for 2500base-x mode by using 1000base-x mode and simply changing frequeny to 3.125 GHz, all this for 88E6393X. The last commit fixes linking when link partner has AN disabled and the device invokes the AN bypass feature. Currently we fail to link in this case. Changes since v1: - fixed wrong operator in patch 3 (thanks Russell) - added more comments about why BMCR_ANENABLE is used in patch 6 (thanks Russell) - updated some return statements from if (something) return func(); return 0; to if (something) err = func(); return err; (err is set to 0 before the condition) ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents b0f38e1 + ede359d commit 74b95b0

File tree

2 files changed

+224
-32
lines changed

2 files changed

+224
-32
lines changed

drivers/net/dsa/mv88e6xxx/serdes.c

Lines changed: 220 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,22 @@ static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
5050
}
5151

5252
static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
53-
u16 status, u16 lpa,
53+
u16 ctrl, u16 status, u16 lpa,
5454
struct phylink_link_state *state)
5555
{
56+
state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
57+
5658
if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
57-
state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
59+
/* The Spped and Duplex Resolved register is 1 if AN is enabled
60+
* and complete, or if AN is disabled. So with disabled AN we
61+
* still get here on link up. But we want to set an_complete
62+
* only if AN was enabled, thus we look at BMCR_ANENABLE.
63+
* (According to 802.3-2008 section 22.2.4.2.10, we should be
64+
* able to get this same value from BMSR_ANEGCAPABLE, but tests
65+
* show that these Marvell PHYs don't conform to this part of
66+
* the specificaion - BMSR_ANEGCAPABLE is simply always 1.)
67+
*/
68+
state->an_complete = !!(ctrl & BMCR_ANENABLE);
5869
state->duplex = status &
5970
MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
6071
DUPLEX_FULL : DUPLEX_HALF;
@@ -81,6 +92,18 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
8192
dev_err(chip->dev, "invalid PHY speed\n");
8293
return -EINVAL;
8394
}
95+
} else if (state->link &&
96+
state->interface != PHY_INTERFACE_MODE_SGMII) {
97+
/* If Speed and Duplex Resolved register is 0 and link is up, it
98+
* means that AN was enabled, but link partner had it disabled
99+
* and the PHY invoked the Auto-Negotiation Bypass feature and
100+
* linked anyway.
101+
*/
102+
state->duplex = DUPLEX_FULL;
103+
if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
104+
state->speed = SPEED_2500;
105+
else
106+
state->speed = SPEED_1000;
84107
} else {
85108
state->link = false;
86109
}
@@ -168,9 +191,15 @@ int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
168191
int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
169192
int lane, struct phylink_link_state *state)
170193
{
171-
u16 lpa, status;
194+
u16 lpa, status, ctrl;
172195
int err;
173196

197+
err = mv88e6352_serdes_read(chip, MII_BMCR, &ctrl);
198+
if (err) {
199+
dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err);
200+
return err;
201+
}
202+
174203
err = mv88e6352_serdes_read(chip, 0x11, &status);
175204
if (err) {
176205
dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err);
@@ -183,7 +212,7 @@ int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port,
183212
return err;
184213
}
185214

186-
return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
215+
return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state);
187216
}
188217

189218
int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port,
@@ -883,9 +912,16 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
883912
static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
884913
int port, int lane, struct phylink_link_state *state)
885914
{
886-
u16 lpa, status;
915+
u16 lpa, status, ctrl;
887916
int err;
888917

918+
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
919+
MV88E6390_SGMII_BMCR, &ctrl);
920+
if (err) {
921+
dev_err(chip->dev, "can't read Serdes PHY control: %d\n", err);
922+
return err;
923+
}
924+
889925
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
890926
MV88E6390_SGMII_PHY_STATUS, &status);
891927
if (err) {
@@ -900,7 +936,7 @@ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
900936
return err;
901937
}
902938

903-
return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state);
939+
return mv88e6xxx_serdes_pcs_get_state(chip, ctrl, status, lpa, state);
904940
}
905941

906942
static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip,
@@ -1271,9 +1307,31 @@ void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p)
12711307
}
12721308
}
12731309

1274-
static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
1310+
static int mv88e6393x_serdes_power_lane(struct mv88e6xxx_chip *chip, int lane,
1311+
bool on)
12751312
{
1276-
u16 reg, pcs;
1313+
u16 reg;
1314+
int err;
1315+
1316+
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
1317+
MV88E6393X_SERDES_CTRL1, &reg);
1318+
if (err)
1319+
return err;
1320+
1321+
if (on)
1322+
reg &= ~(MV88E6393X_SERDES_CTRL1_TX_PDOWN |
1323+
MV88E6393X_SERDES_CTRL1_RX_PDOWN);
1324+
else
1325+
reg |= MV88E6393X_SERDES_CTRL1_TX_PDOWN |
1326+
MV88E6393X_SERDES_CTRL1_RX_PDOWN;
1327+
1328+
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
1329+
MV88E6393X_SERDES_CTRL1, reg);
1330+
}
1331+
1332+
static int mv88e6393x_serdes_erratum_4_6(struct mv88e6xxx_chip *chip, int lane)
1333+
{
1334+
u16 reg;
12771335
int err;
12781336

12791337
/* mv88e6393x family errata 4.6:
@@ -1284,26 +1342,45 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
12841342
* It seems that after this workaround the SERDES is automatically
12851343
* powered up (the bit is cleared), so power it down.
12861344
*/
1287-
if (lane == MV88E6393X_PORT0_LANE || lane == MV88E6393X_PORT9_LANE ||
1288-
lane == MV88E6393X_PORT10_LANE) {
1289-
err = mv88e6390_serdes_read(chip, lane,
1290-
MDIO_MMD_PHYXS,
1291-
MV88E6393X_SERDES_POC, &reg);
1292-
if (err)
1293-
return err;
1345+
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
1346+
MV88E6393X_SERDES_POC, &reg);
1347+
if (err)
1348+
return err;
12941349

1295-
reg &= ~MV88E6393X_SERDES_POC_PDOWN;
1296-
reg |= MV88E6393X_SERDES_POC_RESET;
1350+
reg &= ~MV88E6393X_SERDES_POC_PDOWN;
1351+
reg |= MV88E6393X_SERDES_POC_RESET;
12971352

1298-
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
1299-
MV88E6393X_SERDES_POC, reg);
1300-
if (err)
1301-
return err;
1353+
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
1354+
MV88E6393X_SERDES_POC, reg);
1355+
if (err)
1356+
return err;
13021357

1303-
err = mv88e6390_serdes_power_sgmii(chip, lane, false);
1304-
if (err)
1305-
return err;
1306-
}
1358+
err = mv88e6390_serdes_power_sgmii(chip, lane, false);
1359+
if (err)
1360+
return err;
1361+
1362+
return mv88e6393x_serdes_power_lane(chip, lane, false);
1363+
}
1364+
1365+
int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip)
1366+
{
1367+
int err;
1368+
1369+
err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT0_LANE);
1370+
if (err)
1371+
return err;
1372+
1373+
err = mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT9_LANE);
1374+
if (err)
1375+
return err;
1376+
1377+
return mv88e6393x_serdes_erratum_4_6(chip, MV88E6393X_PORT10_LANE);
1378+
}
1379+
1380+
static int mv88e6393x_serdes_erratum_4_8(struct mv88e6xxx_chip *chip, int lane)
1381+
{
1382+
u16 reg, pcs;
1383+
int err;
13071384

13081385
/* mv88e6393x family errata 4.8:
13091386
* When a SERDES port is operating in 1000BASE-X or SGMII mode link may
@@ -1334,38 +1411,149 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
13341411
MV88E6393X_ERRATA_4_8_REG, reg);
13351412
}
13361413

1337-
int mv88e6393x_serdes_setup_errata(struct mv88e6xxx_chip *chip)
1414+
static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane,
1415+
u8 cmode)
1416+
{
1417+
static const struct {
1418+
u16 dev, reg, val, mask;
1419+
} fixes[] = {
1420+
{ MDIO_MMD_VEND1, 0x8093, 0xcb5a, 0xffff },
1421+
{ MDIO_MMD_VEND1, 0x8171, 0x7088, 0xffff },
1422+
{ MDIO_MMD_VEND1, 0x80c9, 0x311a, 0xffff },
1423+
{ MDIO_MMD_VEND1, 0x80a2, 0x8000, 0xff7f },
1424+
{ MDIO_MMD_VEND1, 0x80a9, 0x0000, 0xfff0 },
1425+
{ MDIO_MMD_VEND1, 0x80a3, 0x0000, 0xf8ff },
1426+
{ MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC,
1427+
MV88E6393X_SERDES_POC_RESET, MV88E6393X_SERDES_POC_RESET },
1428+
};
1429+
int err, i;
1430+
u16 reg;
1431+
1432+
/* mv88e6393x family errata 5.2:
1433+
* For optimal signal integrity the following sequence should be applied
1434+
* to SERDES operating in 10G mode. These registers only apply to 10G
1435+
* operation and have no effect on other speeds.
1436+
*/
1437+
if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER)
1438+
return 0;
1439+
1440+
for (i = 0; i < ARRAY_SIZE(fixes); ++i) {
1441+
err = mv88e6390_serdes_read(chip, lane, fixes[i].dev,
1442+
fixes[i].reg, &reg);
1443+
if (err)
1444+
return err;
1445+
1446+
reg &= ~fixes[i].mask;
1447+
reg |= fixes[i].val;
1448+
1449+
err = mv88e6390_serdes_write(chip, lane, fixes[i].dev,
1450+
fixes[i].reg, reg);
1451+
if (err)
1452+
return err;
1453+
}
1454+
1455+
return 0;
1456+
}
1457+
1458+
static int mv88e6393x_serdes_fix_2500basex_an(struct mv88e6xxx_chip *chip,
1459+
int lane, u8 cmode, bool on)
13381460
{
1461+
u16 reg;
13391462
int err;
13401463

1341-
err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT0_LANE);
1464+
if (cmode != MV88E6XXX_PORT_STS_CMODE_2500BASEX)
1465+
return 0;
1466+
1467+
/* Inband AN is broken on Amethyst in 2500base-x mode when set by
1468+
* standard mechanism (via cmode).
1469+
* We can get around this by configuring the PCS mode to 1000base-x
1470+
* and then writing value 0x58 to register 1e.8000. (This must be done
1471+
* while SerDes receiver and transmitter are disabled, which is, when
1472+
* this function is called.)
1473+
* It seem that when we do this configuration to 2500base-x mode (by
1474+
* changing PCS mode to 1000base-x and frequency to 3.125 GHz from
1475+
* 1.25 GHz) and then configure to sgmii or 1000base-x, the device
1476+
* thinks that it already has SerDes at 1.25 GHz and does not change
1477+
* the 1e.8000 register, leaving SerDes at 3.125 GHz.
1478+
* To avoid this, change PCS mode back to 2500base-x when disabling
1479+
* SerDes from 2500base-x mode.
1480+
*/
1481+
err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS,
1482+
MV88E6393X_SERDES_POC, &reg);
1483+
if (err)
1484+
return err;
1485+
1486+
reg &= ~(MV88E6393X_SERDES_POC_PCS_MASK | MV88E6393X_SERDES_POC_AN);
1487+
if (on)
1488+
reg |= MV88E6393X_SERDES_POC_PCS_1000BASEX |
1489+
MV88E6393X_SERDES_POC_AN;
1490+
else
1491+
reg |= MV88E6393X_SERDES_POC_PCS_2500BASEX;
1492+
reg |= MV88E6393X_SERDES_POC_RESET;
1493+
1494+
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
1495+
MV88E6393X_SERDES_POC, reg);
13421496
if (err)
13431497
return err;
13441498

1345-
err = mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT9_LANE);
1499+
err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_VEND1, 0x8000, 0x58);
13461500
if (err)
13471501
return err;
13481502

1349-
return mv88e6393x_serdes_port_errata(chip, MV88E6393X_PORT10_LANE);
1503+
return 0;
13501504
}
13511505

13521506
int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane,
13531507
bool on)
13541508
{
13551509
u8 cmode = chip->ports[port].cmode;
1510+
int err;
13561511

13571512
if (port != 0 && port != 9 && port != 10)
13581513
return -EOPNOTSUPP;
13591514

1515+
if (on) {
1516+
err = mv88e6393x_serdes_erratum_4_8(chip, lane);
1517+
if (err)
1518+
return err;
1519+
1520+
err = mv88e6393x_serdes_erratum_5_2(chip, lane, cmode);
1521+
if (err)
1522+
return err;
1523+
1524+
err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
1525+
true);
1526+
if (err)
1527+
return err;
1528+
1529+
err = mv88e6393x_serdes_power_lane(chip, lane, true);
1530+
if (err)
1531+
return err;
1532+
}
1533+
13601534
switch (cmode) {
13611535
case MV88E6XXX_PORT_STS_CMODE_SGMII:
13621536
case MV88E6XXX_PORT_STS_CMODE_1000BASEX:
13631537
case MV88E6XXX_PORT_STS_CMODE_2500BASEX:
1364-
return mv88e6390_serdes_power_sgmii(chip, lane, on);
1538+
err = mv88e6390_serdes_power_sgmii(chip, lane, on);
1539+
break;
13651540
case MV88E6393X_PORT_STS_CMODE_5GBASER:
13661541
case MV88E6393X_PORT_STS_CMODE_10GBASER:
1367-
return mv88e6390_serdes_power_10g(chip, lane, on);
1542+
err = mv88e6390_serdes_power_10g(chip, lane, on);
1543+
break;
13681544
}
13691545

1370-
return 0;
1546+
if (err)
1547+
return err;
1548+
1549+
if (!on) {
1550+
err = mv88e6393x_serdes_power_lane(chip, lane, false);
1551+
if (err)
1552+
return err;
1553+
1554+
err = mv88e6393x_serdes_fix_2500basex_an(chip, lane, cmode,
1555+
false);
1556+
}
1557+
1558+
return err;
13711559
}

drivers/net/dsa/mv88e6xxx/serdes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@
9393
#define MV88E6393X_SERDES_POC_PCS_MASK 0x0007
9494
#define MV88E6393X_SERDES_POC_RESET BIT(15)
9595
#define MV88E6393X_SERDES_POC_PDOWN BIT(5)
96+
#define MV88E6393X_SERDES_POC_AN BIT(3)
97+
#define MV88E6393X_SERDES_CTRL1 0xf003
98+
#define MV88E6393X_SERDES_CTRL1_TX_PDOWN BIT(9)
99+
#define MV88E6393X_SERDES_CTRL1_RX_PDOWN BIT(8)
96100

97101
#define MV88E6393X_ERRATA_4_8_REG 0xF074
98102
#define MV88E6393X_ERRATA_4_8_BIT BIT(14)

0 commit comments

Comments
 (0)