realtek: phy: add RTL8218D initialization

The RTL8218D currently relies on proper U-Boot configuration. In
case that is not possible, provide a basic setup sequence that can
bring the PHY "alive". The SDK provides multiple configuration
sequences for two operation modes (XSGMII or QSGMII) and the different
SoC families. Due to limited testing resources only provide a setup
for RTL93xx devices and both modes at the moment.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://github.com/openwrt/openwrt/pull/21551
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Markus Stockhausen 2026-01-15 18:25:31 +01:00 committed by Robert Marko
parent 3af12632ef
commit 3ddcd5265f

View file

@ -738,6 +738,68 @@ static int rtl821x_config_init(struct phy_device *phydev)
return 0;
}
static int rtl8218d_config_init(struct phy_device *phydev)
{
int oldpage, oldxpage;
bool is_qsgmii;
int chip_info;
rtl821x_config_init(phydev);
if (phydev->mdio.addr % 8)
return 0;
/*
* The RTl8218D has two MAC (aka SoC side) operation modes. Either dual QSGMII
* or single XSGMII (Realtek proprietary) link. The mode is usually configured via
* strapping pins CHIP_MODE1/2. For the moment offer a configuration that at least
* works for RTL93xx devices. This sequence even "revives" a PHY that has been hard
* reset with
*
* phy_write(phydev, 0x1e, 0x8);
* phy_write_paged(phydev, 0x262, 0x10, 0x1);
*/
oldpage = phy_read(phydev, RTL8XXX_PAGE_SELECT);
oldxpage = phy_read(phydev, RTL821XEXT_MEDIA_PAGE_SELECT);
phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, 0x8);
chip_info = phy_read_paged(phydev, 0x327, 0x15);
is_qsgmii = (phy_read_paged(phydev, 0x260, 0x12) & 0xf0) == 0xd0;
pr_info("RTL8218D (chip_id=%d, rev_id=%d) on port %d running in %s mode\n",
(chip_info >> 7) & 0x7, chip_info & 0x7f, phydev->mdio.addr,
is_qsgmii ? "QSGMII" : "XSGMII");
if (is_qsgmii) {
for (int sds = 0; sds < 2; sds++) {
/* unknown amplification value */
phy_modify_paged(phydev, 0x4a8 + sds * 0x100, 0x12, BIT(3), 0);
/* main aplification */
phy_modify_paged(phydev, 0x4ab + sds * 0x100, 0x16, 0x3e0, 0x1e0);
/* unknown LCCMU value */
phy_write_paged(phydev, 0x4ac + sds * 0x100, 0x15, 0x4380);
}
} else {
/* serdes 0/1 disable auto negotiation */
phy_modify_paged(phydev, 0x400, 0x12, 0, BIT(8));
phy_modify_paged(phydev, 0x500, 0x12, 0, BIT(8));
/* unknown eye configuration */
phy_modify_paged(phydev, 0x4b8, 0x12, BIT(3), 0);
}
/* reset serdes 0 */
phy_write_paged(phydev, 0x400, 0x10, 0x1700);
phy_write_paged(phydev, 0x400, 0x10, 0x1703);
/* reset serdes 1 */
phy_write_paged(phydev, 0x500, 0x10, 0x1400);
phy_write_paged(phydev, 0x500, 0x10, 0x1403);
phy_write(phydev, RTL821XEXT_MEDIA_PAGE_SELECT, oldxpage);
phy_write(phydev, RTL8XXX_PAGE_SELECT, oldpage);
return 0;
}
static void rtl8218b_cmu_reset(struct phy_device *phydev, int reset_id)
{
int bitpos = reset_id * 2;
@ -896,7 +958,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
{
PHY_ID_MATCH_EXACT(PHY_ID_RTL8218D),
.name = "REALTEK RTL8218D",
.config_init = rtl821x_config_init,
.config_init = rtl8218d_config_init,
.features = PHY_GBIT_FEATURES,
.probe = rtl8218x_phy_probe,
.read_mmd = rtl821x_read_mmd,