From: Markus Stockhausen Date: Sun, 11 Jan 2026 09:40:12 +0000 (+0100) Subject: realtek: mdio: provide phy info helper X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93711307e0c116591d7a4c452dbbfe76273b33ef;p=thirdparty%2Fopenwrt.git realtek: mdio: provide phy info helper The mdio driver currently initializes the phy polling registers with some nasty magic. It identifies the interface mode from the dts and draws some strange conclusions. Looking at the SDK one can see that this is basically dependent of the attached phy type. So the code location is quite right inside the mdio driver. Provide a new get_phy_info() function that determines the phy characteristics that are important for the polling unit . It will be later needed by the RTL93xx setup code. Some explanation about the fields of the structure: - has_res_reg: phy has a special Realtek resolution polling register. It is unclear if this gives more details or if it simply allows faster polling. - has_giga_lite: This is a phy that allows for Realtek proprietary 1G/2.5G lite connectivity. In this case data is only transmitted over two wire pairs. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/21469 Signed-off-by: Stijn Tintel --- diff --git a/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c index 09a0bc602cc..9d1b61dc1b2 100644 --- a/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c +++ b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto.c @@ -12,6 +12,19 @@ #define RTMDIO_MAX_SMI_BUS 4 #define RTMDIO_PAGE_SELECT 0x1f +#define RTMDIO_PHY_AQR113C 0x31c31c12 +#define RTMDIO_PHY_RTL8221B_VB_CG 0x001cc849 +#define RTMDIO_PHY_RTL8221B_VM_CG 0x001cc84a +#define RTMDIO_PHY_RTL8224 0x001ccad0 +#define RTMDIO_PHY_RTL8226 0x001cc838 +#define RTMDIO_PHY_RTL8218D 0x001cc983 +#define RTMDIO_PHY_RTL8218E 0x001cc984 + +#define RTMDIO_PHY_MAC_1G 3 +#define RTMDIO_PHY_MAC_2G_PLUS 1 + +#define RTMDIO_PHY_POLL_MMD(dev, reg, bit) ((bit << 21) | (dev << 16) | reg) + /* Register base */ #define RTMDIO_SW_BASE ((volatile void *) 0xBB000000) @@ -150,6 +163,17 @@ struct rtmdio_config { int (*write_phy)(u32 port, u32 page, u32 reg, u32 val); }; +struct rtmdio_phy_info { + unsigned int phy_id; + bool phy_unknown; + int mac_type; + bool has_giga_lite; + bool has_res_reg; + unsigned int poll_duplex; + unsigned int poll_adv_1000; + unsigned int poll_lpa_1000; +}; + /* RTL838x specific MDIO functions */ static int rtmdio_838x_smi_wait_op(int timeout) @@ -764,6 +788,57 @@ static int rtmdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) return 0; } +__maybe_unused +static void rtmdio_get_phy_info(struct mii_bus *bus, int addr, struct rtmdio_phy_info *phyinfo) +{ + struct rtmdio_bus_priv *priv = bus->priv; + + /* + * Depending on the attached PHY the polling mechanism must be fine tuned. Basically + * this boils down to which registers must be read and if there are any special + * features. + */ + memset(phyinfo, 0, sizeof(*phyinfo)); + if (priv->smi_bus[addr] < 0) { + phyinfo->phy_unknown = true; + return; + } + + if (priv->smi_bus_isc45[priv->smi_bus[addr]]) + phyinfo->phy_id = (rtmdio_read_c45(bus, addr, 31, 2) << 16) + + rtmdio_read_c45(bus, addr, 31, 3); + else + phyinfo->phy_id = (rtmdio_read(bus, addr, 2) << 16) + + rtmdio_read(bus, addr, 3); + + switch(phyinfo->phy_id) { + case RTMDIO_PHY_AQR113C: + phyinfo->mac_type = RTMDIO_PHY_MAC_2G_PLUS; + phyinfo->poll_duplex = RTMDIO_PHY_POLL_MMD(1, 0x0000, 8); + phyinfo->poll_adv_1000 = RTMDIO_PHY_POLL_MMD(7, 0xc400, 15); + phyinfo->poll_lpa_1000 = RTMDIO_PHY_POLL_MMD(7, 0xe820, 15); + break; + case RTMDIO_PHY_RTL8218D: + case RTMDIO_PHY_RTL8218E: + phyinfo->mac_type = RTMDIO_PHY_MAC_1G; + phyinfo->has_giga_lite = true; + break; + case RTMDIO_PHY_RTL8226: + case RTMDIO_PHY_RTL8221B_VB_CG: + case RTMDIO_PHY_RTL8221B_VM_CG: + case RTMDIO_PHY_RTL8224: + phyinfo->mac_type = RTMDIO_PHY_MAC_2G_PLUS; + phyinfo->has_giga_lite = true; + phyinfo->poll_duplex = RTMDIO_PHY_POLL_MMD(31, 0xa400, 8); + phyinfo->poll_adv_1000 = RTMDIO_PHY_POLL_MMD(31, 0xa412, 9); + phyinfo->poll_lpa_1000 = RTMDIO_PHY_POLL_MMD(31, 0xa414, 11); + break; + default: + phyinfo->phy_unknown = true; + break; + } +} + static int rtmdio_838x_reset(struct mii_bus *bus) { pr_debug("%s called\n", __func__);