realtek: phy: add RTL8214FC initialization for RTL839x

Until now the RTL8214FC is initialized either by U-Boot (all
devices) or by some magic firmware file (RTL838x). On RTL839x
devices without U-Boot (e.g. ZyXEL GS1920) this PHY cannot
be used.

Provide the most basic setup sequence for RTL839x so that
copper/fiber work. Later it can be taken over for all devices
and the firmware helpers can be dropped.

Remark! This should not (but might) break RTL839x devices with
RTL8214FC U-Boot setup.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/21435
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
This commit is contained in:
Markus Stockhausen 2026-01-07 08:32:58 +01:00 committed by Stijn Tintel
parent 4fa90d879b
commit 0bab65dfa7

View file

@ -811,20 +811,6 @@ static const struct sfp_upstream_ops rtl8214fc_sfp_ops = {
.module_remove = rtl8214fc_sfp_remove,
};
static int rtl8214fc_phy_probe(struct phy_device *phydev)
{
int ret = 0;
if (rtl821x_package_join(phydev, 4) == RTL821X_JOIN_LAST) {
if (soc_info.family == RTL8380_FAMILY_ID)
ret = rtl8380_configure_rtl8214fc(get_base_phy(phydev));
if (ret)
return ret;
}
return phy_sfp_probe(phydev, &rtl8214fc_sfp_ops);
}
static int rtl8214c_phy_probe(struct phy_device *phydev)
{
if (rtl821x_package_join(phydev, 4) == RTL821X_JOIN_LAST)
@ -931,6 +917,58 @@ static int rtl8218b_config_init(struct phy_device *phydev)
return 0;
}
static int rtl8214fc_config_init(struct phy_device *phydev)
{
static int regs[] = {16, 19, 20, 21};
struct phy_device *portphy;
int port;
/* Hardware is similar to RTL8218B reuse coding for serdes and copper init */
rtl8218b_config_init(phydev);
if (phydev->mdio.addr % 8)
return 0;
for (port = 0; port < 4; port++) {
portphy = get_package_phy(phydev, port);
phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8);
/* setup basic fiber control in base phy and default to copper */
phy_write_paged(phydev, 0x266, regs[port], 0x0f95);
phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x0);
phy_write(portphy, RTL821XEXT_MEDIA_PAGE_SELECT, 0x3);
/* set fiber SerDes RX to negative edge */
phy_modify_paged(portphy, 0x8, 0x17, 0, BIT(14));
/* auto negotiation disable link on */
phy_modify_paged(portphy, 0x8, 0x14, 0, BIT(2));
/* disable fiber 100MBit */
phy_modify_paged(portphy, 0x8, 0x11, BIT(5), 0);
phy_write(portphy, RTL821XEXT_MEDIA_PAGE_SELECT, 0x0);
/* Disable EEE. 0xa5d/0x10 is the same as MDIO_MMD_AN / MDIO_AN_EEE_ADV */
phy_write_paged(portphy, 0xa5d, 0x10, 0x0000);
}
return 0;
}
static int rtl8214fc_phy_probe(struct phy_device *phydev)
{
int ret = 0;
if (rtl821x_package_join(phydev, 4) == RTL821X_JOIN_LAST) {
if (soc_info.family == RTL8380_FAMILY_ID)
ret = rtl8380_configure_rtl8214fc(get_base_phy(phydev));
else if (soc_info.family == RTL8390_FAMILY_ID)
ret = rtl8214fc_config_init(get_base_phy(phydev));
if (ret)
return ret;
}
return phy_sfp_probe(phydev, &rtl8214fc_sfp_ops);
}
static struct phy_driver rtl83xx_phy_driver[] = {
{
PHY_ID_MATCH_EXACT(PHY_ID_RTL8214C),