diff options
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c | 101 |
1 files changed, 69 insertions, 32 deletions
diff --git a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c index dfec2e55ee..0d9ced9b6c 100644 --- a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c @@ -47,6 +47,8 @@ extern struct rtl83xx_soc_info soc_info; #define RX_EN_93XX 0x10 #define TX_DO 0x2 #define WRAP 0x2 +#define MAX_PORTS 57 +#define MAX_SMI_BUSSES 4 #define RING_BUFFER 1600 @@ -185,6 +187,10 @@ struct rtl838x_eth_priv { u32 lastEvent; u16 rxrings; u16 rxringlen; + u8 smi_bus[MAX_PORTS]; + u8 smi_addr[MAX_PORTS]; + bool smi_bus_isc45[MAX_SMI_BUSSES]; + bool phy_is_internal[MAX_PORTS]; }; extern int rtl838x_phy_init(struct rtl838x_eth_priv *priv); @@ -1727,52 +1733,56 @@ static int rtl930x_mdio_reset(struct mii_bus *bus) { int i; int pos; + struct rtl838x_eth_priv *priv = bus->priv; + u32 c45_mask = 0; + u32 poll_sel[2]; + u32 poll_ctrl = 0; - pr_info("RTL930X_SMI_PORT0_15_POLLING_SEL %08x 16-27: %08x\n", - sw_r32(RTL930X_SMI_PORT0_15_POLLING_SEL), - sw_r32(RTL930X_SMI_PORT16_27_POLLING_SEL)); + // Mapping of port to phy-addresses on an SMI bus + poll_sel[0] = poll_sel[1] = 0; + for (i = 0; i < 28; i++) { + pos = (i % 6) * 5; + sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos, + RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4); - pr_info("%s: Enable SMI polling on SMI bus 0, SMI1, SMI2, disable on SMI3\n", __func__); - sw_w32_mask(BIT(20) | BIT(21) | BIT(22), BIT(23), RTL930X_SMI_GLB_CTRL); + pos = (i * 2) % 32; + poll_sel[i / 16] |= priv->smi_bus[i] << pos; + poll_ctrl |= BIT(20 + priv->smi_bus[i]); + } - pr_info("RTL9300 Powering on SerDes ports\n"); - rtl9300_sds_power(24, 1); - rtl9300_sds_power(25, 1); - rtl9300_sds_power(26, 1); - rtl9300_sds_power(27, 1); - mdelay(200); + // Configure which SMI bus is behind which port number + sw_w32(poll_sel[0], RTL930X_SMI_PORT0_15_POLLING_SEL); + sw_w32(poll_sel[1], RTL930X_SMI_PORT16_27_POLLING_SEL); - // RTL930X_SMI_PORT0_15_POLLING_SEL 55550000 16-27: 00f9aaaa - // i.e SMI=0 for all ports - for (i = 0; i < 5; i++) - pr_info("port phy: %08x\n", sw_r32(RTL930X_SMI_PORT0_5_ADDR + i *4)); + // Enable polling on the respective SMI busses + sw_w32_mask(0, poll_ctrl, RTL930X_SMI_GLB_CTRL); - // 1-to-1 mapping of port to phy-address - for (i = 0; i < 24; i++) { - pos = (i % 6) * 5; - sw_w32_mask(0x1f << pos, i << pos, RTL930X_SMI_PORT0_5_ADDR + (i / 6) * 4); - } + // Configure which SMI busses are polled in c45 based on a c45 PHY being on that bus + for (i = 0; i < 4; i++) + if (priv->smi_bus_isc45[i]) + c45_mask |= BIT(i + 16); - // ports 24 and 25 have PHY addresses 8 and 9, ports 26/27 PHY 26/27 - sw_w32(8 | 9 << 5 | 26 << 10 | 27 << 15, RTL930X_SMI_PORT0_5_ADDR + 4 * 4); + pr_info("c45_mask: %08x\n", c45_mask); + sw_w32_mask(0, c45_mask, RTL930X_SMI_GLB_CTRL); - // Ports 24 and 25 live on SMI bus 1 and 2 - sw_w32_mask(0x3 << 16, 0x1 << 16, RTL930X_SMI_PORT16_27_POLLING_SEL); - sw_w32_mask(0x3 << 18, 0x2 << 18, RTL930X_SMI_PORT16_27_POLLING_SEL); - - // SMI bus 1 and 2 speak Clause 45 TODO: Configure from .dts - sw_w32_mask(0, BIT(17) | BIT(18), RTL930X_SMI_GLB_CTRL); + // Ports 24 to 27 are 2.5 or 10Gig, set this type (1) or (0) for internal SerDes + for (i = 24; i < 28; i++) { + pos = (i - 24) * 3 + 12; + if (priv->phy_is_internal[i]) + sw_w32_mask(0x7 << pos, 0 << pos, RTL930X_SMI_MAC_TYPE_CTRL); + else + sw_w32_mask(0x7 << pos, 1 << pos, RTL930X_SMI_MAC_TYPE_CTRL); + } - // Ports 24 and 25 are 2.5 Gig, set this type (1) - sw_w32_mask(0x7 << 12, 1 << 12, RTL930X_SMI_MAC_TYPE_CTRL); - sw_w32_mask(0x7 << 15, 1 << 15, RTL930X_SMI_MAC_TYPE_CTRL); + // TODO: Set up RTL9300_SMI_10GPHY_POLLING_SEL_0 for Aquantia PHYs on e.g. XGS 1250 return 0; } static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) { - struct device_node *mii_np; + struct device_node *mii_np, *dn; + u32 pn; int ret; pr_debug("%s called\n", __func__); @@ -1825,6 +1835,33 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) priv->mii_bus->priv = priv; priv->mii_bus->parent = &priv->pdev->dev; + for_each_node_by_name(dn, "ethernet-phy") { + u32 smi_addr[2]; + + if (of_property_read_u32(dn, "reg", &pn)) + continue; + + if (of_property_read_u32_array(dn, "rtl9300,smi-address", &smi_addr[0], 2)) { + smi_addr[0] = 0; + smi_addr[1] = pn; + } + + if (pn < MAX_PORTS) { + priv->smi_bus[pn] = smi_addr[0]; + priv->smi_addr[pn] = smi_addr[1]; + } else { + pr_err("%s: illegal port number %d\n", __func__, pn); + } + + if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45")) + priv->smi_bus_isc45[smi_addr[0]] = true; + + if (of_property_read_bool(dn, "phy-is-integrated")) { + priv->phy_is_internal[pn] = true; + } + + } + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); ret = of_mdiobus_register(priv->mii_bus, mii_np); |