Skip to content

Commit c9e934f

Browse files
plappermaulrobimarko
authored andcommitted
realtek: 6.12: refactor EEE for RTL8218B/D and RTL8214FC
Three different code paths for the same phy model. Now the bus is prepared to handle c45 (mmd) read/writes correctly. Remove the custom implementations and let generic kernel functions do their best. To achieve this - disable the PHY-mode EEE in rtl821x_config_init() as upstream does - provide mmd read/write functions that avoid EEE via c45 over c22 While chaning the phy_driver functions sort them alphabetically. Signed-off-by: Markus Stockhausen <[email protected]> Link: openwrt#18935 Signed-off-by: Robert Marko <[email protected]>
1 parent ec310a0 commit c9e934f

File tree

1 file changed

+71
-226
lines changed

1 file changed

+71
-226
lines changed

target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c

Lines changed: 71 additions & 226 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ extern int phy_port_read_paged(struct phy_device *phydev, int port, int page, u3
5252
#define RTL821XINT_MEDIA_PAGE_SELECT 0x1d
5353
/* external RTL821X PHY uses register 0x1e to select media page */
5454
#define RTL821XEXT_MEDIA_PAGE_SELECT 0x1e
55+
#define RTL821X_PHYCR2 0x19
56+
#define RTL821X_PHYCR2_PHY_EEE_ENABLE BIT(5)
5557

5658
#define RTL821X_CHIP_ID 0x6276
5759

@@ -1160,231 +1162,61 @@ static int rtl8214fc_config_aneg(struct phy_device *phydev)
11601162
return ret;
11611163
}
11621164

1163-
/* Enable EEE on the RTL8218B PHYs
1164-
* The method used is not the preferred way (which would be based on the MAC-EEE state,
1165-
* but the only way that works since the kernel first enables EEE in the MAC
1166-
* and then sets up the PHY. The MAC-based approach would require the oppsite.
1167-
*/
1168-
static void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
1169-
{
1170-
u32 val;
1171-
bool an_enabled;
1172-
1173-
pr_debug("In %s %d, enable %d\n", __func__, phydev->mdio.addr, enable);
1174-
/* Set GPHY page to copper */
1175-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
1176-
1177-
val = phy_read(phydev, MII_BMCR);
1178-
an_enabled = val & BMCR_ANENABLE;
1179-
1180-
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
1181-
val |= MDIO_EEE_1000T | MDIO_EEE_100TX;
1182-
phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, enable ? (MDIO_EEE_100TX | MDIO_EEE_1000T) : 0);
1183-
1184-
/* 500M EEE ability */
1185-
val = phy_read_paged(phydev, RTL821X_PAGE_GPHY, 20);
1186-
if (enable)
1187-
val |= BIT(7);
1188-
else
1189-
val &= ~BIT(7);
1190-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, 20, val);
1191-
1192-
/* Restart AN if enabled */
1193-
if (an_enabled) {
1194-
val = phy_read(phydev, MII_BMCR);
1195-
val |= BMCR_ANRESTART;
1196-
phy_write(phydev, MII_BMCR, val);
1197-
}
1198-
1199-
/* GPHY page back to auto */
1200-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
1201-
}
1202-
1203-
static int rtl8218b_get_eee(struct phy_device *phydev, struct ethtool_keee *e)
1204-
{
1205-
u32 val;
1206-
int addr = phydev->mdio.addr;
1207-
1208-
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
1209-
1210-
/* Set GPHY page to copper */
1211-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
1212-
1213-
val = phy_read_paged(phydev, 7, MDIO_AN_EEE_ADV);
1214-
if (e->eee_enabled) {
1215-
/* Verify vs MAC-based EEE */
1216-
e->eee_enabled = !!(val & BIT(7));
1217-
if (!e->eee_enabled) {
1218-
val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
1219-
e->eee_enabled = !!(val & BIT(4));
1220-
}
1221-
}
1222-
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
1223-
1224-
/* GPHY page to auto */
1225-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
1226-
1227-
return 0;
1228-
}
1229-
1230-
static int rtl8218d_get_eee(struct phy_device *phydev, struct ethtool_keee *e)
1165+
static int rtl821x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
12311166
{
1232-
u32 val;
1167+
struct mii_bus *bus = phydev->mdio.bus;
12331168
int addr = phydev->mdio.addr;
1169+
int ret;
12341170

1235-
pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
1236-
1237-
/* Set GPHY page to copper */
1238-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
1239-
1240-
val = phy_read_paged(phydev, 7, MDIO_AN_EEE_ADV);
1241-
if (e->eee_enabled)
1242-
e->eee_enabled = !!(val & BIT(7));
1243-
pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
1244-
1245-
/* GPHY page to auto */
1246-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
1247-
1248-
return 0;
1249-
}
1250-
1251-
static int rtl8214fc_set_eee(struct phy_device *phydev, struct ethtool_keee *e)
1252-
{
1253-
u32 poll_state;
1254-
int port = phydev->mdio.addr;
1255-
bool an_enabled;
1256-
u32 val;
1257-
1258-
pr_debug("In %s port %d, enabled %d\n", __func__, port, e->eee_enabled);
1259-
1260-
if (rtl8214fc_media_is_fibre(phydev)) {
1261-
netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", port);
1262-
return -ENOTSUPP;
1263-
}
1264-
1265-
poll_state = disable_polling(port);
1266-
1267-
/* Set GPHY page to copper */
1268-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
1269-
1270-
/* Get auto-negotiation status */
1271-
val = phy_read(phydev, MII_BMCR);
1272-
an_enabled = val & BMCR_ANENABLE;
1273-
1274-
pr_info("%s: aneg: %d\n", __func__, an_enabled);
1275-
val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
1276-
val &= ~BIT(5); /* Use MAC-based EEE */
1277-
phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
1278-
1279-
/* Enable 100M (bit 1) / 1000M (bit 2) EEE */
1280-
phy_write_paged(phydev, 7, MDIO_AN_EEE_ADV, e->eee_enabled ? (MDIO_EEE_100TX | MDIO_EEE_1000T) : 0);
1171+
/*
1172+
* The RTL821x PHYs are usually only C22 capable and are defined accordingly in DTS.
1173+
* Nevertheless GPL source drops clearly indicate that EEE features can be accessed
1174+
* directly via C45. Testing shows that C45 over C22 (as used in kernel EEE framework)
1175+
* works as well but only as long as PHY polling is disabled in the SOC. To avoid ugly
1176+
* hacks pass through C45 accesses for important EEE registers. Maybe some day the mdio
1177+
* bus can intercept these patterns and switch off/on polling on demand. That way this
1178+
* phy device driver can avoid handling special cases on its own.
1179+
*/
12811180

1282-
/* 500M EEE ability */
1283-
val = phy_read_paged(phydev, RTL821X_PAGE_GPHY, 20);
1284-
if (e->eee_enabled)
1285-
val |= BIT(7);
1181+
if ((devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) ||
1182+
(devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) ||
1183+
(devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE))
1184+
ret = __mdiobus_c45_read(bus, addr, devnum, regnum);
12861185
else
1287-
val &= ~BIT(7);
1288-
1289-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, 20, val);
1290-
1291-
/* Restart AN if enabled */
1292-
if (an_enabled) {
1293-
pr_info("%s: doing aneg\n", __func__);
1294-
val = phy_read(phydev, MII_BMCR);
1295-
val |= BMCR_ANRESTART;
1296-
phy_write(phydev, MII_BMCR, val);
1297-
}
1298-
1299-
/* GPHY page back to auto */
1300-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XINT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
1301-
1302-
resume_polling(poll_state);
1186+
ret = -EOPNOTSUPP;
13031187

1304-
return 0;
1188+
return ret;
13051189
}
13061190

1307-
static int rtl8214fc_get_eee(struct phy_device *phydev, struct ethtool_keee *e)
1191+
static int rtl821x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val)
13081192
{
1193+
struct mii_bus *bus = phydev->mdio.bus;
13091194
int addr = phydev->mdio.addr;
1195+
int ret;
13101196

1311-
pr_debug("In %s port %d, enabled %d\n", __func__, addr, e->eee_enabled);
1312-
if (rtl8214fc_media_is_fibre(phydev)) {
1313-
netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", addr);
1314-
return -ENOTSUPP;
1315-
}
1197+
/* see rtl821x_read_mmd() */
1198+
if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
1199+
ret = __mdiobus_c45_write(bus, addr, devnum, regnum, val);
1200+
else
1201+
ret = -EOPNOTSUPP;
13161202

1317-
return rtl8218b_get_eee(phydev, e);
1203+
return ret;
13181204
}
13191205

1320-
static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_keee *e)
1206+
static int rtl8214fc_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
13211207
{
1322-
int port = phydev->mdio.addr;
1323-
u64 poll_state;
1324-
u32 val;
1325-
bool an_enabled;
1326-
1327-
pr_info("In %s, port %d, enabled %d\n", __func__, port, e->eee_enabled);
1328-
1329-
poll_state = disable_polling(port);
1330-
1331-
/* Set GPHY page to copper */
1332-
phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_COPPER);
1333-
val = phy_read(phydev, MII_BMCR);
1334-
an_enabled = val & BMCR_ANENABLE;
1335-
1336-
if (e->eee_enabled) {
1337-
/* 100/1000M EEE Capability */
1338-
phy_write(phydev, 13, 0x0007);
1339-
phy_write(phydev, 14, 0x003C);
1340-
phy_write(phydev, 13, 0x4007);
1341-
phy_write(phydev, 14, 0x0006);
1342-
1343-
val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
1344-
val |= BIT(4);
1345-
phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
1346-
} else {
1347-
/* 100/1000M EEE Capability */
1348-
phy_write(phydev, 13, 0x0007);
1349-
phy_write(phydev, 14, 0x003C);
1350-
phy_write(phydev, 13, 0x0007);
1351-
phy_write(phydev, 14, 0x0000);
1352-
1353-
val = phy_read_paged(phydev, RTL821X_PAGE_MAC, 25);
1354-
val &= ~BIT(4);
1355-
phy_write_paged(phydev, RTL821X_PAGE_MAC, 25, val);
1356-
}
1357-
1358-
/* Restart AN if enabled */
1359-
if (an_enabled) {
1360-
val = phy_read(phydev, MII_BMCR);
1361-
val |= BMCR_ANRESTART;
1362-
phy_write(phydev, MII_BMCR, val);
1363-
}
1364-
1365-
/* GPHY page back to auto */
1366-
phy_write_paged(phydev, RTL821X_PAGE_GPHY, RTL821XEXT_MEDIA_PAGE_SELECT, RTL821X_MEDIA_PAGE_AUTO);
1367-
1368-
pr_info("%s done\n", __func__);
1369-
resume_polling(poll_state);
1208+
if (__rtl8214fc_media_is_fibre(phydev))
1209+
return -EOPNOTSUPP;
13701210

1371-
return 0;
1211+
return rtl821x_read_mmd(phydev, devnum, regnum);
13721212
}
13731213

1374-
static int rtl8218d_set_eee(struct phy_device *phydev, struct ethtool_keee *e)
1214+
static int rtl8214fc_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val)
13751215
{
1376-
int addr = phydev->mdio.addr;
1377-
u64 poll_state;
1378-
1379-
pr_info("In %s, port %d, enabled %d\n", __func__, addr, e->eee_enabled);
1380-
1381-
poll_state = disable_polling(addr);
1382-
1383-
rtl8218d_eee_set(phydev, (bool) e->eee_enabled);
1384-
1385-
resume_polling(poll_state);
1216+
if (__rtl8214fc_media_is_fibre(phydev))
1217+
return -EOPNOTSUPP;
13861218

1387-
return 0;
1219+
return rtl821x_write_mmd(phydev, devnum, regnum, val);
13881220
}
13891221

13901222
static int rtl8380_configure_rtl8214c(struct phy_device *phydev)
@@ -3884,6 +3716,15 @@ static int rtl8218d_phy_probe(struct phy_device *phydev)
38843716
return 0;
38853717
}
38863718

3719+
static int rtl821x_config_init(struct phy_device *phydev)
3720+
{
3721+
/* Disable PHY-mode EEE so LPI is passed to the MAC */
3722+
phy_modify_paged(phydev, RTL821X_PAGE_MAC, RTL821X_PHYCR2,
3723+
RTL821X_PHYCR2_PHY_EEE_ENABLE, 0);
3724+
3725+
return 0;
3726+
}
3727+
38873728
static int rtl838x_serdes_probe(struct phy_device *phydev)
38883729
{
38893730
int addr = phydev->mdio.addr;
@@ -3955,41 +3796,57 @@ static struct phy_driver rtl83xx_phy_driver[] = {
39553796
.match_phy_device = rtl8214fc_match_phy_device,
39563797
.name = "Realtek RTL8214FC",
39573798
.config_aneg = rtl8214fc_config_aneg,
3958-
.get_eee = rtl8214fc_get_eee,
3799+
.config_init = rtl821x_config_init,
39593800
.get_features = rtl8214fc_get_features,
39603801
.get_tunable = rtl8214fc_get_tunable,
39613802
.probe = rtl8214fc_phy_probe,
3803+
.read_mmd = rtl8214fc_read_mmd,
39623804
.read_page = rtl821x_read_page,
39633805
.read_status = rtl8214fc_read_status,
39643806
.resume = rtl8214fc_resume,
3965-
.set_eee = rtl8214fc_set_eee,
39663807
.set_tunable = rtl8214fc_set_tunable,
39673808
.suspend = rtl8214fc_suspend,
3809+
.write_mmd = rtl8214fc_write_mmd,
39683810
.write_page = rtl821x_write_page,
39693811
},
39703812
{
39713813
.match_phy_device = rtl8218b_ext_match_phy_device,
39723814
.name = "Realtek RTL8218B (external)",
3815+
.config_init = rtl821x_config_init,
39733816
.features = PHY_GBIT_FEATURES,
39743817
.probe = rtl8218b_ext_phy_probe,
3818+
.read_mmd = rtl821x_read_mmd,
39753819
.read_page = rtl821x_read_page,
3976-
.write_page = rtl821x_write_page,
3820+
.resume = genphy_resume,
39773821
.suspend = genphy_suspend,
3822+
.write_mmd = rtl821x_write_mmd,
3823+
.write_page = rtl821x_write_page,
3824+
},
3825+
{
3826+
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
3827+
.name = "Realtek RTL8218B (internal)",
3828+
.config_init = rtl821x_config_init,
3829+
.features = PHY_GBIT_FEATURES,
3830+
.probe = rtl8218b_int_phy_probe,
3831+
.read_mmd = rtl821x_read_mmd,
3832+
.read_page = rtl821x_read_page,
39783833
.resume = genphy_resume,
3979-
.set_eee = rtl8218b_set_eee,
3980-
.get_eee = rtl8218b_get_eee,
3834+
.suspend = genphy_suspend,
3835+
.write_mmd = rtl821x_write_mmd,
3836+
.write_page = rtl821x_write_page,
39813837
},
39823838
{
39833839
PHY_ID_MATCH_EXACT(PHY_ID_RTL8218D),
39843840
.name = "REALTEK RTL8218D",
3841+
.config_init = rtl821x_config_init,
39853842
.features = PHY_GBIT_FEATURES,
39863843
.probe = rtl8218d_phy_probe,
3844+
.read_mmd = rtl821x_read_mmd,
39873845
.read_page = rtl821x_read_page,
3988-
.write_page = rtl821x_write_page,
3989-
.suspend = genphy_suspend,
39903846
.resume = genphy_resume,
3991-
.set_eee = rtl8218d_set_eee,
3992-
.get_eee = rtl8218d_get_eee,
3847+
.suspend = genphy_suspend,
3848+
.write_mmd = rtl821x_write_mmd,
3849+
.write_page = rtl821x_write_page,
39933850
},
39943851
{
39953852
PHY_ID_MATCH_MODEL(PHY_ID_RTL8221B),
@@ -4017,18 +3874,6 @@ static struct phy_driver rtl83xx_phy_driver[] = {
40173874
.set_eee = rtl8226_set_eee,
40183875
.get_eee = rtl8226_get_eee,
40193876
},
4020-
{
4021-
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
4022-
.name = "Realtek RTL8218B (internal)",
4023-
.features = PHY_GBIT_FEATURES,
4024-
.probe = rtl8218b_int_phy_probe,
4025-
.read_page = rtl821x_read_page,
4026-
.write_page = rtl821x_write_page,
4027-
.suspend = genphy_suspend,
4028-
.resume = genphy_resume,
4029-
.set_eee = rtl8218b_set_eee,
4030-
.get_eee = rtl8218b_get_eee,
4031-
},
40323877
{
40333878
PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
40343879
.name = "Realtek RTL8380 SERDES",

0 commit comments

Comments
 (0)