diff options
author | Birger Koblitz <git@birger-koblitz.de> | 2022-01-02 19:12:48 +0100 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2022-02-17 15:21:47 +0000 |
commit | 0536c582e673aa292377f4b8cb11002238a39d32 (patch) | |
tree | b9bcbb5b0a708834373a31d43ad881f3fc9b4fab /target/linux | |
parent | 1b1f05f6826e35eefbf74a68ee313f9f2cc29b5d (diff) | |
download | upstream-0536c582e673aa292377f4b8cb11002238a39d32.tar.gz upstream-0536c582e673aa292377f4b8cb11002238a39d32.tar.bz2 upstream-0536c582e673aa292377f4b8cb11002238a39d32.zip |
realtek: Fix RTL931X Ethernet driver
Various fixes to enable Ethernet on the RTL931X:
- Network start and stop sequence for RTL931X HW
- MDIO access on RTL931X SoC
- Chip initialization
- SerDes setup
Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c | 188 |
1 files changed, 167 insertions, 21 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 39d28ae896..6db2b2a1fe 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 @@ -693,7 +693,7 @@ static void rtl838x_hw_reset(struct rtl838x_eth_priv *priv) sw_w32(0, RTL838X_DMA_IF_RX_RING_SIZE); // Disabled on RTL8380 if (priv->family_id == RTL8390_FAMILY_ID) sw_w32(0xffffffff, RTL839X_DMA_IF_RX_RING_CNTR); - if (priv->family_id == RTL9300_FAMILY_ID) { + if (priv->family_id == RTL9300_FAMILY_ID || priv->family_id == RTL9310_FAMILY_ID) { for (i = 0; i < priv->rxrings; i++) { pos = (i % 3) * 10; sw_w32_mask(0x3ff << pos, 0, priv->r->dma_if_rx_ring_size(i)); @@ -806,8 +806,15 @@ static void rtl93xx_hw_en_rxtx(struct rtl838x_eth_priv *priv) /* Restart TX/RX to CPU port, enable CRC checking */ sw_w32_mask(0x0, 0x3 | BIT(4), priv->r->mac_port_ctrl(priv->cpu_port)); - sw_w32_mask(0, BIT(priv->cpu_port), RTL930X_L2_UNKN_UC_FLD_PMSK); - sw_w32(0x217, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); + if (priv->family_id == RTL9300_FAMILY_ID) + sw_w32_mask(0, BIT(priv->cpu_port), RTL930X_L2_UNKN_UC_FLD_PMSK); + else + sw_w32_mask(0, BIT(priv->cpu_port), RTL931X_L2_UNKN_UC_FLD_PMSK); + + if (priv->family_id == RTL9300_FAMILY_ID) + sw_w32(0x217, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); + else + sw_w32(0x2a1d, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); } static void rtl838x_setup_ring_buffer(struct rtl838x_eth_priv *priv, struct ring_b *ring) @@ -924,10 +931,20 @@ static int rtl838x_eth_open(struct net_device *ndev) sw_w32((0x2 << 3) | 0x2, RTL930X_VLAN_APP_PKT_CTRL); break; + case RTL9310_FAMILY_ID: rtl93xx_hw_en_rxtx(priv); + + // Trap MLD and IGMP messages to CPU_PORT + sw_w32((0x2 << 3) | 0x2, RTL931X_VLAN_APP_PKT_CTRL); + + // Disable External CPU access to switch, clear EXT_CPU_EN + sw_w32_mask(BIT(2), 0, RTL931X_MAC_L2_GLOBAL_CTRL2); + + // Set PCIE_PWR_DOWN + sw_w32_mask(0, BIT(1), RTL931X_PS_SOC_CTRL); break; - } + } netif_tx_start_all_queues(ndev); @@ -976,8 +993,10 @@ static void rtl838x_hw_stop(struct rtl838x_eth_priv *priv) /* CPU-Port: Link down */ if (priv->family_id == RTL8380_FAMILY_ID || priv->family_id == RTL8390_FAMILY_ID) sw_w32(force_mac, priv->r->mac_force_mode_ctrl + priv->cpu_port * 4); - else + else if (priv->family_id == RTL9300_FAMILY_ID) sw_w32_mask(0x3, 0, priv->r->mac_force_mode_ctrl + priv->cpu_port *4); + else if (priv->family_id == RTL9310_FAMILY_ID) + sw_w32_mask(BIT(0) | BIT(9), 0, priv->r->mac_force_mode_ctrl + priv->cpu_port *4); mdelay(100); /* Disable all TX/RX interrupts */ @@ -1465,6 +1484,15 @@ static void rtl838x_mac_pcs_get_state(struct phylink_config *config, case 2: state->speed = SPEED_1000; break; + case 5: + state->speed = SPEED_2500; + break; + case 6: + state->speed = SPEED_5000; + break; + case 4: + state->speed = SPEED_10000; + break; default: state->speed = SPEED_UNKNOWN; break; @@ -1554,12 +1582,16 @@ static int rtl8380_init_mac(struct rtl838x_eth_priv *priv) if (priv->family_id == 0x8390) return rtl8390_init_mac(priv); + // At present we do not know how to set up EEE on any other SoC than RTL8380 + if (priv->family_id != 0x8380) + return 0; + pr_info("%s\n", __func__); /* fix timer for EEE */ sw_w32(0x5001411, RTL838X_EEE_TX_TIMER_GIGA_CTRL); sw_w32(0x5001417, RTL838X_EEE_TX_TIMER_GELITE_CTRL); - /* Init VLAN */ + /* Init VLAN. TODO: Understand what is being done, here */ if (priv->id == 0x8382) { for (i = 0; i <= 28; i++) sw_w32(0, 0xd57c + i * 0x80); @@ -1622,32 +1654,50 @@ static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { u32 val; int err; + struct rtl838x_eth_priv *priv = bus->priv; - // TODO: These are hard-coded for the 2 Fibre Ports of the XGS1210 - if (mii_id >= 26 && mii_id <= 27) - return rtl930x_read_sds_phy(mii_id - 18, 0, regnum); + if (priv->phy_is_internal[mii_id]) + return rtl930x_read_sds_phy(priv->sds_id[mii_id], 0, regnum); if (regnum & MII_ADDR_C45) { regnum &= ~MII_ADDR_C45; err = rtl930x_read_mmd_phy(mii_id, regnum >> 16, regnum & 0xffff, &val); + pr_debug("MMD: %d register %d read %x, err %d\n", mii_id, regnum & 0xffff, val, err); } else { err = rtl930x_read_phy(mii_id, 0, regnum, &val); + pr_debug("PHY: %d register %d read %x, err %d\n", mii_id, regnum, val, err); } if (err) return err; return val; } + static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { u32 val; - int err; -// struct rtl838x_eth_priv *priv = bus->priv; + int err, v; + struct rtl838x_eth_priv *priv = bus->priv; -// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) -// return rtl839x_read_sds_phy(mii_id, regnum); + pr_debug("%s: In here, port %d\n", __func__, mii_id); + if (priv->sds_id[mii_id] >= 0 && mii_id >= 52) { + v = rtl931x_read_sds_phy(priv->sds_id[mii_id], 0, regnum); + if (v < 0) { + err = v; + } else { + err = 0; + val = v; + } + } else { + if (regnum & MII_ADDR_C45) { + regnum &= ~MII_ADDR_C45; + err = rtl931x_read_mmd_phy(mii_id, regnum >> 16, regnum & 0xffff, &val); + } else { + err = rtl931x_read_phy(mii_id, 0, regnum, &val); + } + pr_debug("%s: phy %d, register %d value %x\n", __func__, mii_id, regnum, val); + } - err = rtl931x_read_phy(mii_id, 0, regnum, &val); if (err) return err; return val; @@ -1682,10 +1732,11 @@ static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id, static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { -// struct rtl838x_eth_priv *priv = bus->priv; + struct rtl838x_eth_priv *priv = bus->priv; + + if (priv->sds_id[mii_id] >= 0) + return rtl930x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value); -// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) -// return rtl839x_write_sds_phy(mii_id, regnum, value); if (regnum & MII_ADDR_C45) { regnum &= ~MII_ADDR_C45; return rtl930x_write_mmd_phy(mii_id, regnum >> 16, regnum & 0xffff, value); @@ -1697,10 +1748,10 @@ static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id, static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { -// struct rtl838x_eth_priv *priv = bus->priv; + struct rtl838x_eth_priv *priv = bus->priv; -// if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393) -// return rtl839x_write_sds_phy(mii_id, regnum, value); + if (priv->sds_id[mii_id] >= 0) + return rtl931x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value); return rtl931x_write_phy(mii_id, 0, regnum, value); } @@ -1784,6 +1835,101 @@ static int rtl930x_mdio_reset(struct mii_bus *bus) return 0; } +static int rtl931x_mdio_reset(struct mii_bus *bus) +{ + int i; + int pos; + struct rtl838x_eth_priv *priv = bus->priv; + u32 c45_mask = 0; + u32 poll_sel[4]; + u32 poll_ctrl = 0; + bool mdc_on[4]; + + pr_info("%s called\n", __func__); + // Disable port polling for configuration purposes + sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL); + sw_w32(0, RTL931X_SMI_PORT_POLLING_CTRL + 4); + msleep(100); + + mdc_on[0] = mdc_on[1] = mdc_on[2] = mdc_on[3] = false; + // Mapping of port to phy-addresses on an SMI bus + poll_sel[0] = poll_sel[1] = poll_sel[2] = poll_sel[3] = 0; + for (i = 0; i < 56; i++) { + pos = (i % 6) * 5; + sw_w32_mask(0x1f << pos, priv->smi_addr[i] << pos, RTL931X_SMI_PORT_ADDR + (i / 6) * 4); + pos = (i * 2) % 32; + poll_sel[i / 16] |= priv->smi_bus[i] << pos; + poll_ctrl |= BIT(20 + priv->smi_bus[i]); + mdc_on[priv->smi_bus[i]] = true; + } + + // Configure which SMI bus is behind which port number + for (i = 0; i < 4; i++) { + pr_info("poll sel %d, %08x\n", i, poll_sel[i]); + sw_w32(poll_sel[i], RTL931X_SMI_PORT_POLLING_SEL + (i * 4)); + } + + // Configure which SMI busses + pr_info("%s: WAS RTL931X_MAC_L2_GLOBAL_CTRL2 %08x\n", __func__, sw_r32(RTL931X_MAC_L2_GLOBAL_CTRL2)); + pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0)); + for (i = 0; i < 4; i++) { + // bus is polled in c45 + if (priv->smi_bus_isc45[i]) + c45_mask |= 0x2 << (i * 2); // Std. C45, non-standard is 0x3 + // Enable bus access via MDC + if (mdc_on[i]) + sw_w32_mask(0, BIT(9 + i), RTL931X_MAC_L2_GLOBAL_CTRL2); + } + + pr_info("%s: RTL931X_MAC_L2_GLOBAL_CTRL2 %08x\n", __func__, sw_r32(RTL931X_MAC_L2_GLOBAL_CTRL2)); + pr_info("c45_mask: %08x, RTL931X_SMI_GLB_CTRL0 was %X", c45_mask, sw_r32(RTL931X_SMI_GLB_CTRL0)); + + /* We have a 10G PHY enable polling + sw_w32(0x01010000, RTL931X_SMI_10GPHY_POLLING_SEL2); + sw_w32(0x01E7C400, RTL931X_SMI_10GPHY_POLLING_SEL3); + sw_w32(0x01E7E820, RTL931X_SMI_10GPHY_POLLING_SEL4); +*/ + sw_w32_mask(0xff, c45_mask, RTL931X_SMI_GLB_CTRL1); + + return 0; +} + +static int rtl931x_chip_init(struct rtl838x_eth_priv *priv) +{ + pr_info("In %s\n", __func__); + + // Initialize Encapsulation memory and wait until finished + sw_w32(0x1, RTL931X_MEM_ENCAP_INIT); + do { } while (sw_r32(RTL931X_MEM_ENCAP_INIT) & 1); + pr_info("%s: init ENCAP done\n", __func__); + + // Initialize Managemen Information Base memory and wait until finished + sw_w32(0x1, RTL931X_MEM_MIB_INIT); + do { } while (sw_r32(RTL931X_MEM_MIB_INIT) & 1); + pr_info("%s: init MIB done\n", __func__); + + // Initialize ACL (PIE) memory and wait until finished + sw_w32(0x1, RTL931X_MEM_ACL_INIT); + do { } while (sw_r32(RTL931X_MEM_ACL_INIT) & 1); + pr_info("%s: init ACL done\n", __func__); + + // Initialize ALE memory and wait until finished + sw_w32(0xFFFFFFFF, RTL931X_MEM_ALE_INIT_0); + do { } while (sw_r32(RTL931X_MEM_ALE_INIT_0)); + sw_w32(0x7F, RTL931X_MEM_ALE_INIT_1); + sw_w32(0x7ff, RTL931X_MEM_ALE_INIT_2); + do { } while (sw_r32(RTL931X_MEM_ALE_INIT_2) & 0x7ff); + pr_info("%s: init ALE done\n", __func__); + + // Enable ESD auto recovery + sw_w32(0x1, RTL931X_MDX_CTRL_RSVD); + + // Init SPI, is this for thermal control or what? + sw_w32_mask(0x7 << 11, 0x2 << 11, RTL931X_SPI_CTRL0); + + return 0; +} + static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) { struct device_node *mii_np, *dn; @@ -1870,7 +2016,6 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) 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); @@ -2108,6 +2253,7 @@ static int __init rtl838x_eth_probe(struct platform_device *pdev) priv->cpu_port = RTL931X_CPU_PORT; priv->r = &rtl931x_reg; dev->netdev_ops = &rtl931x_eth_netdev_ops; + rtl931x_chip_init(priv); break; default: pr_err("Unknown SoC family\n"); |