@@ -50,11 +50,22 @@ static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip,
50
50
}
51
51
52
52
static int mv88e6xxx_serdes_pcs_get_state (struct mv88e6xxx_chip * chip ,
53
- u16 status , u16 lpa ,
53
+ u16 ctrl , u16 status , u16 lpa ,
54
54
struct phylink_link_state * state )
55
55
{
56
+ state -> link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK );
57
+
56
58
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 );
58
69
state -> duplex = status &
59
70
MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
60
71
DUPLEX_FULL : DUPLEX_HALF ;
@@ -81,6 +92,18 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
81
92
dev_err (chip -> dev , "invalid PHY speed\n" );
82
93
return - EINVAL ;
83
94
}
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 ;
84
107
} else {
85
108
state -> link = false;
86
109
}
@@ -168,9 +191,15 @@ int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
168
191
int mv88e6352_serdes_pcs_get_state (struct mv88e6xxx_chip * chip , int port ,
169
192
int lane , struct phylink_link_state * state )
170
193
{
171
- u16 lpa , status ;
194
+ u16 lpa , status , ctrl ;
172
195
int err ;
173
196
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
+
174
203
err = mv88e6352_serdes_read (chip , 0x11 , & status );
175
204
if (err ) {
176
205
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,
183
212
return err ;
184
213
}
185
214
186
- return mv88e6xxx_serdes_pcs_get_state (chip , status , lpa , state );
215
+ return mv88e6xxx_serdes_pcs_get_state (chip , ctrl , status , lpa , state );
187
216
}
188
217
189
218
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,
883
912
static int mv88e6390_serdes_pcs_get_state_sgmii (struct mv88e6xxx_chip * chip ,
884
913
int port , int lane , struct phylink_link_state * state )
885
914
{
886
- u16 lpa , status ;
915
+ u16 lpa , status , ctrl ;
887
916
int err ;
888
917
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
+
889
925
err = mv88e6390_serdes_read (chip , lane , MDIO_MMD_PHYXS ,
890
926
MV88E6390_SGMII_PHY_STATUS , & status );
891
927
if (err ) {
@@ -900,7 +936,7 @@ static int mv88e6390_serdes_pcs_get_state_sgmii(struct mv88e6xxx_chip *chip,
900
936
return err ;
901
937
}
902
938
903
- return mv88e6xxx_serdes_pcs_get_state (chip , status , lpa , state );
939
+ return mv88e6xxx_serdes_pcs_get_state (chip , ctrl , status , lpa , state );
904
940
}
905
941
906
942
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)
1271
1307
}
1272
1308
}
1273
1309
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 )
1275
1312
{
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 ;
1277
1335
int err ;
1278
1336
1279
1337
/* mv88e6393x family errata 4.6:
@@ -1284,26 +1342,45 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane)
1284
1342
* It seems that after this workaround the SERDES is automatically
1285
1343
* powered up (the bit is cleared), so power it down.
1286
1344
*/
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 ;
1294
1349
1295
- reg &= ~MV88E6393X_SERDES_POC_PDOWN ;
1296
- reg |= MV88E6393X_SERDES_POC_RESET ;
1350
+ reg &= ~MV88E6393X_SERDES_POC_PDOWN ;
1351
+ reg |= MV88E6393X_SERDES_POC_RESET ;
1297
1352
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 ;
1302
1357
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 ;
1307
1384
1308
1385
/* mv88e6393x family errata 4.8:
1309
1386
* 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)
1334
1411
MV88E6393X_ERRATA_4_8_REG , reg );
1335
1412
}
1336
1413
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 )
1338
1460
{
1461
+ u16 reg ;
1339
1462
int err ;
1340
1463
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 );
1342
1496
if (err )
1343
1497
return err ;
1344
1498
1345
- err = mv88e6393x_serdes_port_errata (chip , MV88E6393X_PORT9_LANE );
1499
+ err = mv88e6390_serdes_write (chip , lane , MDIO_MMD_VEND1 , 0x8000 , 0x58 );
1346
1500
if (err )
1347
1501
return err ;
1348
1502
1349
- return mv88e6393x_serdes_port_errata ( chip , MV88E6393X_PORT10_LANE ) ;
1503
+ return 0 ;
1350
1504
}
1351
1505
1352
1506
int mv88e6393x_serdes_power (struct mv88e6xxx_chip * chip , int port , int lane ,
1353
1507
bool on )
1354
1508
{
1355
1509
u8 cmode = chip -> ports [port ].cmode ;
1510
+ int err ;
1356
1511
1357
1512
if (port != 0 && port != 9 && port != 10 )
1358
1513
return - EOPNOTSUPP ;
1359
1514
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
+
1360
1534
switch (cmode ) {
1361
1535
case MV88E6XXX_PORT_STS_CMODE_SGMII :
1362
1536
case MV88E6XXX_PORT_STS_CMODE_1000BASEX :
1363
1537
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 ;
1365
1540
case MV88E6393X_PORT_STS_CMODE_5GBASER :
1366
1541
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 ;
1368
1544
}
1369
1545
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 ;
1371
1559
}
0 commit comments