diff options
Diffstat (limited to 'drivers/net/ethernet/mediatek')
-rw-r--r-- | drivers/net/ethernet/mediatek/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_path.c | 45 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_soc.c | 348 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_soc.h | 79 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_star_emac.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_wed.c | 28 | ||||
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 36 |
7 files changed, 387 insertions, 154 deletions
diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig index 7bfd3f230ff5..2ba361f8ce7d 100644 --- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig @@ -17,6 +17,7 @@ config NET_MEDIATEK_SOC select PINCTRL select PHYLINK select DIMLIB + select GENERIC_ALLOCATOR select PAGE_POOL select PAGE_POOL_STATS select PCS_MTK_LYNXI diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c index 7c27a19c4d8f..b4c01e2878f6 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_path.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c @@ -14,7 +14,7 @@ struct mtk_eth_muxc { const char *name; - int cap_bit; + u64 cap_bit; int (*set_path)(struct mtk_eth *eth, u64 path); }; @@ -31,6 +31,8 @@ static const char *mtk_eth_path_name(u64 path) return "gmac2_rgmii"; case MTK_ETH_PATH_GMAC2_SGMII: return "gmac2_sgmii"; + case MTK_ETH_PATH_GMAC2_2P5GPHY: + return "gmac2_2p5gphy"; case MTK_ETH_PATH_GMAC2_GEPHY: return "gmac2_gephy"; case MTK_ETH_PATH_GDM1_ESW: @@ -127,6 +129,29 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) return 0; } +static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path) +{ + int ret; + + if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) { + ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_GMAC2_V2); + if (ret) + return ret; + + /* Setup mux to 2p5g PHY */ + ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, + MUX_G2_USXGMII_SEL); + if (ret) + return ret; + + dev_dbg(eth->dev, "path %s in %s updated\n", + mtk_eth_path_name(path), __func__); + } + + return 0; +} + static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) { unsigned int val = 0; @@ -210,6 +235,10 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, .set_path = set_mux_u3_gmac2_to_qphy, }, { + .name = "mux_gmac2_to_2p5gphy", + .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, + .set_path = set_mux_gmac2_to_2p5gphy, + }, { .name = "mux_gmac1_gmac2_to_sgmii_rgmii", .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, @@ -260,6 +289,20 @@ int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) return mtk_eth_mux_setup(eth, path); } +int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id) +{ + u64 path = 0; + + if (mac_id == MTK_GMAC2_ID) + path = MTK_ETH_PATH_GMAC2_2P5GPHY; + + if (!path) + return -EINVAL; + + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); +} + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) { u64 path = 0; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 6c92072b4c28..5a5fcde76dc0 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -27,6 +27,7 @@ #include <net/dsa.h> #include <net/dst_metadata.h> #include <net/page_pool/helpers.h> +#include <linux/genalloc.h> #include "mtk_eth_soc.h" #include "mtk_wed.h" @@ -503,7 +504,7 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, static void mtk_setup_bridge_switch(struct mtk_eth *eth) { /* Force Port1 XGMAC Link Up */ - mtk_m32(eth, 0, MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID), + mtk_m32(eth, 0, MTK_XGMAC_FORCE_MODE(MTK_GMAC1_ID), MTK_XGMAC_STS(MTK_GMAC1_ID)); /* Adjust GSW bridge IPG to 11 */ @@ -532,6 +533,26 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, return NULL; } +static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode, + phy_interface_t iface) +{ + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + struct mtk_eth *eth = mac->hw; + + if (mtk_interface_mode_is_xgmii(eth, iface) && + mac->id != MTK_GMAC1_ID) { + mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, + XMAC_MCR_TRX_DISABLE, MTK_XMAC_MCR(mac->id)); + + mtk_m32(mac->hw, MTK_XGMAC_FORCE_MODE(mac->id) | + MTK_XGMAC_FORCE_LINK(mac->id), + MTK_XGMAC_FORCE_MODE(mac->id), MTK_XGMAC_STS(mac->id)); + } + + return 0; +} + static void mtk_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { @@ -573,6 +594,12 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, } break; case PHY_INTERFACE_MODE_INTERNAL: + if (mac->id == MTK_GMAC2_ID && + MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) { + err = mtk_gmac_2p5gphy_path_setup(eth, mac->id); + if (err) + goto init_err; + } break; default: goto err_phy; @@ -644,12 +671,12 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, } /* Setup gmac */ - if (mtk_is_netsys_v3_or_greater(eth) && - mac->interface == PHY_INTERFACE_MODE_INTERNAL) { + if (mtk_interface_mode_is_xgmii(eth, state->interface)) { mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); - mtk_setup_bridge_switch(eth); + if (mac->id == MTK_GMAC1_ID) + mtk_setup_bridge_switch(eth); } return; @@ -696,10 +723,19 @@ static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, { struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); - u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK); - mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + if (!mtk_interface_mode_is_xgmii(mac->hw, interface)) { + /* GMAC modes */ + mtk_m32(mac->hw, + MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK, 0, + MTK_MAC_MCR(mac->id)); + } else if (mac->id != MTK_GMAC1_ID) { + /* XGMAC except for built-in switch */ + mtk_m32(mac->hw, XMAC_MCR_TRX_DISABLE, XMAC_MCR_TRX_DISABLE, + MTK_XMAC_MCR(mac->id)); + mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), 0, + MTK_XGMAC_STS(mac->id)); + } } static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, @@ -771,13 +807,12 @@ static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); } -static void mtk_mac_link_up(struct phylink_config *config, - struct phy_device *phy, - unsigned int mode, phy_interface_t interface, - int speed, int duplex, bool tx_pause, bool rx_pause) +static void mtk_gdm_mac_link_up(struct mtk_mac *mac, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, + bool rx_pause) { - struct mtk_mac *mac = container_of(config, struct mtk_mac, - phylink_config); u32 mcr; mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); @@ -811,6 +846,56 @@ static void mtk_mac_link_up(struct phylink_config *config, mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } +static void mtk_xgdm_mac_link_up(struct mtk_mac *mac, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, + bool rx_pause) +{ + u32 mcr; + + if (mac->id == MTK_GMAC1_ID) + return; + + /* Eliminate the interference(before link-up) caused by PHY noise */ + mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id)); + mdelay(20); + mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, + MTK_XMAC_CNT_CTRL(mac->id)); + + mtk_m32(mac->hw, MTK_XGMAC_FORCE_LINK(mac->id), + MTK_XGMAC_FORCE_LINK(mac->id), MTK_XGMAC_STS(mac->id)); + + mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id)); + mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC | + XMAC_MCR_TRX_DISABLE); + /* Configure pause modes - + * phylink will avoid these for half duplex + */ + if (tx_pause) + mcr |= XMAC_MCR_FORCE_TX_FC; + if (rx_pause) + mcr |= XMAC_MCR_FORCE_RX_FC; + + mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id)); +} + +static void mtk_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, bool tx_pause, bool rx_pause) +{ + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + + if (mtk_interface_mode_is_xgmii(mac->hw, interface)) + mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex, + tx_pause, rx_pause); + else + mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex, + tx_pause, rx_pause); +} + static void mtk_mac_disable_tx_lpi(struct phylink_config *config) { struct mtk_mac *mac = container_of(config, struct mtk_mac, @@ -828,6 +913,9 @@ static int mtk_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, struct mtk_eth *eth = mac->hw; u32 val; + if (mtk_interface_mode_is_xgmii(eth, mac->interface)) + return -EOPNOTSUPP; + /* Tx idle timer in ms */ timer = DIV_ROUND_UP(timer, 1000); @@ -858,6 +946,7 @@ static int mtk_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, } static const struct phylink_mac_ops mtk_phylink_ops = { + .mac_prepare = mtk_mac_prepare, .mac_select_pcs = mtk_mac_select_pcs, .mac_config = mtk_mac_config, .mac_finish = mtk_mac_finish, @@ -1179,6 +1268,34 @@ static void *mtk_max_lro_buf_alloc(gfp_t gfp_mask) return (void *)data; } +static void *mtk_dma_ring_alloc(struct mtk_eth *eth, size_t size, + dma_addr_t *dma_handle, bool use_sram) +{ + void *dma_ring; + + if (use_sram && eth->sram_pool) { + dma_ring = (void *)gen_pool_alloc(eth->sram_pool, size); + if (!dma_ring) + return dma_ring; + *dma_handle = gen_pool_virt_to_phys(eth->sram_pool, + (unsigned long)dma_ring); + } else { + dma_ring = dma_alloc_coherent(eth->dma_dev, size, dma_handle, + GFP_KERNEL); + } + + return dma_ring; +} + +static void mtk_dma_ring_free(struct mtk_eth *eth, size_t size, void *dma_ring, + dma_addr_t dma_handle, bool in_sram) +{ + if (in_sram && eth->sram_pool) + gen_pool_free(eth->sram_pool, (unsigned long)dma_ring, size); + else + dma_free_coherent(eth->dma_dev, size, dma_ring, dma_handle); +} + /* the qdma core needs scratch memory to be setup */ static int mtk_init_fq_dma(struct mtk_eth *eth) { @@ -1188,13 +1305,8 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) dma_addr_t dma_addr; int i, j, len; - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) - eth->scratch_ring = eth->sram_base; - else - eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, - cnt * soc->tx.desc_size, - ð->phy_scratch_ring, - GFP_KERNEL); + eth->scratch_ring = mtk_dma_ring_alloc(eth, cnt * soc->tx.desc_size, + ð->phy_scratch_ring, true); if (unlikely(!eth->scratch_ring)) return -ENOMEM; @@ -2532,14 +2644,7 @@ static int mtk_tx_alloc(struct mtk_eth *eth) if (!ring->buf) goto no_tx_mem; - if (MTK_HAS_CAPS(soc->caps, MTK_SRAM)) { - ring->dma = eth->sram_base + soc->tx.fq_dma_size * sz; - ring->phys = eth->phy_scratch_ring + soc->tx.fq_dma_size * (dma_addr_t)sz; - } else { - ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz, - &ring->phys, GFP_KERNEL); - } - + ring->dma = mtk_dma_ring_alloc(eth, ring_size * sz, &ring->phys, true); if (!ring->dma) goto no_tx_mem; @@ -2638,10 +2743,10 @@ static void mtk_tx_clean(struct mtk_eth *eth) kfree(ring->buf); ring->buf = NULL; } - if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && ring->dma) { - dma_free_coherent(eth->dma_dev, - ring->dma_size * soc->tx.desc_size, - ring->dma, ring->phys); + + if (ring->dma) { + mtk_dma_ring_free(eth, ring->dma_size * soc->tx.desc_size, + ring->dma, ring->phys, true); ring->dma = NULL; } @@ -2658,14 +2763,9 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) const struct mtk_reg_map *reg_map = eth->soc->reg_map; const struct mtk_soc_data *soc = eth->soc; struct mtk_rx_ring *ring; - int rx_data_len, rx_dma_size, tx_ring_size; + int rx_data_len, rx_dma_size; int i; - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) - tx_ring_size = MTK_QDMA_RING_SIZE; - else - tx_ring_size = soc->tx.dma_size; - if (rx_flag == MTK_RX_FLAGS_QDMA) { if (ring_no) return -EINVAL; @@ -2700,20 +2800,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) ring->page_pool = pp; } - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) || - rx_flag != MTK_RX_FLAGS_NORMAL) { - ring->dma = dma_alloc_coherent(eth->dma_dev, - rx_dma_size * eth->soc->rx.desc_size, - &ring->phys, GFP_KERNEL); - } else { - struct mtk_tx_ring *tx_ring = ð->tx_ring; - - ring->dma = tx_ring->dma + tx_ring_size * - eth->soc->tx.desc_size * (ring_no + 1); - ring->phys = tx_ring->phys + tx_ring_size * - eth->soc->tx.desc_size * (ring_no + 1); - } - + ring->dma = mtk_dma_ring_alloc(eth, + rx_dma_size * eth->soc->rx.desc_size, + &ring->phys, + rx_flag == MTK_RX_FLAGS_NORMAL); if (!ring->dma) return -ENOMEM; @@ -2828,10 +2918,9 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_ ring->data = NULL; } - if (!in_sram && ring->dma) { - dma_free_coherent(eth->dma_dev, - ring->dma_size * eth->soc->rx.desc_size, - ring->dma, ring->phys); + if (ring->dma) { + mtk_dma_ring_free(eth, ring->dma_size * eth->soc->rx.desc_size, + ring->dma, ring->phys, in_sram); ring->dma = NULL; } @@ -3199,15 +3288,16 @@ static void mtk_dma_free(struct mtk_eth *eth) netdev_tx_reset_subqueue(eth->netdev[i], j); } - if (!MTK_HAS_CAPS(soc->caps, MTK_SRAM) && eth->scratch_ring) { - dma_free_coherent(eth->dma_dev, - MTK_QDMA_RING_SIZE * soc->tx.desc_size, - eth->scratch_ring, eth->phy_scratch_ring); + if (eth->scratch_ring) { + mtk_dma_ring_free(eth, soc->tx.fq_dma_size * soc->tx.desc_size, + eth->scratch_ring, eth->phy_scratch_ring, + true); eth->scratch_ring = NULL; eth->phy_scratch_ring = 0; } + mtk_tx_clean(eth); - mtk_rx_clean(eth, ð->rx_ring[0], MTK_HAS_CAPS(soc->caps, MTK_SRAM)); + mtk_rx_clean(eth, ð->rx_ring[0], true); mtk_rx_clean(eth, ð->rx_ring_qdma, false); if (eth->hwlro) { @@ -3248,6 +3338,53 @@ static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue) schedule_work(ð->pending_work); } +static int mtk_get_irqs(struct platform_device *pdev, struct mtk_eth *eth) +{ + int i; + + /* future SoCs beginning with MT7988 should use named IRQs in dts */ + eth->irq[MTK_FE_IRQ_TX] = platform_get_irq_byname_optional(pdev, "fe1"); + eth->irq[MTK_FE_IRQ_RX] = platform_get_irq_byname_optional(pdev, "fe2"); + if (eth->irq[MTK_FE_IRQ_TX] >= 0 && eth->irq[MTK_FE_IRQ_RX] >= 0) + return 0; + + /* only use legacy mode if platform_get_irq_byname_optional returned -ENXIO */ + if (eth->irq[MTK_FE_IRQ_TX] != -ENXIO) + return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_TX], + "Error requesting FE TX IRQ\n"); + + if (eth->irq[MTK_FE_IRQ_RX] != -ENXIO) + return dev_err_probe(&pdev->dev, eth->irq[MTK_FE_IRQ_RX], + "Error requesting FE RX IRQ\n"); + + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) + dev_warn(&pdev->dev, "legacy DT: missing interrupt-names."); + + /* legacy way: + * On MTK_SHARED_INT SoCs (MT7621 + MT7628) the first IRQ is taken + * from devicetree and used for both RX and TX - it is shared. + * On SoCs with non-shared IRQs the first entry is not used, + * the second is for TX, and the third is for RX. + */ + for (i = 0; i < MTK_FE_IRQ_NUM; i++) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { + if (i == MTK_FE_IRQ_SHARED) + eth->irq[MTK_FE_IRQ_SHARED] = platform_get_irq(pdev, i); + else + eth->irq[i] = eth->irq[MTK_FE_IRQ_SHARED]; + } else { + eth->irq[i] = platform_get_irq(pdev, i + 1); + } + + if (eth->irq[i] < 0) { + dev_err(&pdev->dev, "no IRQ%d resource found\n", i); + return -ENXIO; + } + } + + return 0; +} + static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) { struct mtk_eth *eth = _eth; @@ -3301,7 +3438,7 @@ static void mtk_poll_controller(struct net_device *dev) mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); mtk_rx_irq_disable(eth, eth->soc->rx.irq_done_mask); - mtk_handle_irq_rx(eth->irq[2], dev); + mtk_handle_irq_rx(eth->irq[MTK_FE_IRQ_RX], dev); mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); mtk_rx_irq_enable(eth, eth->soc->rx.irq_done_mask); } @@ -4768,6 +4905,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->phylink = phylink; + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && + id == MTK_GMAC2_ID) + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + mac->phylink_config.supported_interfaces); + SET_NETDEV_DEV(eth->netdev[id], eth->dev); eth->netdev[id]->watchdog_timeo = 5 * HZ; eth->netdev[id]->netdev_ops = &mtk_netdev_ops; @@ -4782,7 +4924,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) eth->netdev[id]->features |= eth->soc->hw_features; eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; - eth->netdev[id]->irq = eth->irq[0]; + eth->netdev[id]->irq = eth->irq[MTK_FE_IRQ_SHARED]; eth->netdev[id]->dev.of_node = np; if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) @@ -4825,7 +4967,7 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) list_add_tail(&dev->close_list, &dev_list); } - dev_close_many(&dev_list, false); + netif_close_many(&dev_list, false); eth->dma_dev = dma_dev; @@ -4867,9 +5009,30 @@ static int mtk_sgmii_init(struct mtk_eth *eth) return 0; } +static int mtk_setup_legacy_sram(struct mtk_eth *eth, struct resource *res) +{ + dev_warn(eth->dev, "legacy DT: using hard-coded SRAM offset.\n"); + + if (res->start + MTK_ETH_SRAM_OFFSET + MTK_ETH_NETSYS_V2_SRAM_SIZE - 1 > + res->end) + return -EINVAL; + + eth->sram_pool = devm_gen_pool_create(eth->dev, + const_ilog2(MTK_ETH_SRAM_GRANULARITY), + NUMA_NO_NODE, dev_name(eth->dev)); + + if (IS_ERR(eth->sram_pool)) + return PTR_ERR(eth->sram_pool); + + return gen_pool_add_virt(eth->sram_pool, + (unsigned long)eth->base + MTK_ETH_SRAM_OFFSET, + res->start + MTK_ETH_SRAM_OFFSET, + MTK_ETH_NETSYS_V2_SRAM_SIZE, NUMA_NO_NODE); +} + static int mtk_probe(struct platform_device *pdev) { - struct resource *res = NULL, *res_sram; + struct resource *res = NULL; struct device_node *mac_np; struct mtk_eth *eth; int err, i; @@ -4889,20 +5052,6 @@ static int mtk_probe(struct platform_device *pdev) if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) eth->ip_align = NET_IP_ALIGN; - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) { - /* SRAM is actual memory and supports transparent access just like DRAM. - * Hence we don't require __iomem being set and don't need to use accessor - * functions to read from or write to SRAM. - */ - if (mtk_is_netsys_v3_or_greater(eth)) { - eth->sram_base = (void __force *)devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(eth->sram_base)) - return PTR_ERR(eth->sram_base); - } else { - eth->sram_base = (void __force *)eth->base + MTK_ETH_SRAM_OFFSET; - } - } - if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) { err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36)); if (!err) @@ -4977,16 +5126,21 @@ static int mtk_probe(struct platform_device *pdev) err = -EINVAL; goto err_destroy_sgmii; } + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM)) { - if (mtk_is_netsys_v3_or_greater(eth)) { - res_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res_sram) { + eth->sram_pool = of_gen_pool_get(pdev->dev.of_node, + "sram", 0); + if (!eth->sram_pool) { + if (!mtk_is_netsys_v3_or_greater(eth)) { + err = mtk_setup_legacy_sram(eth, res); + if (err) + goto err_destroy_sgmii; + } else { + dev_err(&pdev->dev, + "Could not get SRAM pool\n"); err = -EINVAL; goto err_destroy_sgmii; } - eth->phy_scratch_ring = res_sram->start; - } else { - eth->phy_scratch_ring = res->start + MTK_ETH_SRAM_OFFSET; } } } @@ -5012,17 +5166,10 @@ static int mtk_probe(struct platform_device *pdev) } } - for (i = 0; i < 3; i++) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0) - eth->irq[i] = eth->irq[0]; - else - eth->irq[i] = platform_get_irq(pdev, i); - if (eth->irq[i] < 0) { - dev_err(&pdev->dev, "no IRQ%d resource found\n", i); - err = -ENXIO; - goto err_wed_exit; - } - } + err = mtk_get_irqs(pdev, eth); + if (err) + goto err_wed_exit; + for (i = 0; i < ARRAY_SIZE(eth->clks); i++) { eth->clks[i] = devm_clk_get(eth->dev, mtk_clks_source_name[i]); @@ -5066,17 +5213,17 @@ static int mtk_probe(struct platform_device *pdev) } if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { - err = devm_request_irq(eth->dev, eth->irq[0], + err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_SHARED], mtk_handle_irq, 0, dev_name(eth->dev), eth); } else { - err = devm_request_irq(eth->dev, eth->irq[1], + err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_TX], mtk_handle_irq_tx, 0, dev_name(eth->dev), eth); if (err) goto err_free_dev; - err = devm_request_irq(eth->dev, eth->irq[2], + err = devm_request_irq(eth->dev, eth->irq[MTK_FE_IRQ_RX], mtk_handle_irq_rx, 0, dev_name(eth->dev), eth); } @@ -5122,7 +5269,7 @@ static int mtk_probe(struct platform_device *pdev) } else netif_info(eth, probe, eth->netdev[i], "mediatek frame engine at 0x%08lx, irq %d\n", - eth->netdev[i]->base_addr, eth->irq[0]); + eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]); } /* we run 2 devices on the same DMA ring so we need a dummy device @@ -5463,3 +5610,4 @@ module_platform_driver(mtk_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC"); +MODULE_IMPORT_NS("NETDEV_INTERNAL"); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 88ef2e9c50fc..0168e2fbc619 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -141,8 +141,10 @@ #define MTK_GDMA_MAC_ADRH(x) ({ typeof(x) _x = (x); (_x == MTK_GMAC3_ID) ? \ 0x54C : 0x50C + (_x * 0x1000); }) -/* Internal SRAM offset */ -#define MTK_ETH_SRAM_OFFSET 0x40000 +/* legacy DT support for internal SRAM */ +#define MTK_ETH_SRAM_OFFSET 0x40000 +#define MTK_ETH_SRAM_GRANULARITY 32 +#define MTK_ETH_NETSYS_V2_SRAM_SIZE 0x40000 /* FE global misc reg*/ #define MTK_FE_GLO_MISC 0x124 @@ -431,7 +433,8 @@ /* XMAC status registers */ #define MTK_XGMAC_STS(x) (((x) == MTK_GMAC3_ID) ? 0x1001C : 0x1000C) -#define MTK_XGMAC_FORCE_LINK(x) (((x) == MTK_GMAC2_ID) ? BIT(31) : BIT(15)) +#define MTK_XGMAC_FORCE_MODE(x) (((x) == MTK_GMAC2_ID) ? BIT(31) : BIT(15)) +#define MTK_XGMAC_FORCE_LINK(x) (((x) == MTK_GMAC2_ID) ? BIT(27) : BIT(11)) #define MTK_USXGMII_PCS_LINK BIT(8) #define MTK_XGMAC_RX_FC BIT(5) #define MTK_XGMAC_TX_FC BIT(4) @@ -524,6 +527,21 @@ #define INTF_MODE_RGMII_1000 (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED) #define INTF_MODE_RGMII_10_100 0 +/* XFI Mac control registers */ +#define MTK_XMAC_BASE(x) (0x12000 + (((x) - 1) * 0x1000)) +#define MTK_XMAC_MCR(x) (MTK_XMAC_BASE(x)) +#define XMAC_MCR_TRX_DISABLE 0xf +#define XMAC_MCR_FORCE_TX_FC BIT(5) +#define XMAC_MCR_FORCE_RX_FC BIT(4) + +/* XFI Mac logic reset registers */ +#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10) +#define XMAC_LOGIC_RST BIT(0) + +/* XFI Mac count global control */ +#define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100) +#define XMAC_GLB_CNTCLR BIT(0) + /* GPIO port control registers for GMAC 2*/ #define GPIO_OD33_CTRL8 0x4c0 #define GPIO_BIAS_CTRL 0xed0 @@ -587,6 +605,10 @@ #define GEPHY_MAC_SEL BIT(1) /* Top misc registers */ +#define TOP_MISC_NETSYS_PCS_MUX 0x0 +#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) +#define MUX_G2_USXGMII_SEL BIT(1) + #define USB_PHY_SWITCH_REG 0x218 #define QPHY_SEL_MASK GENMASK(1, 0) #define SGMII_QPHY_SEL 0x2 @@ -622,6 +644,11 @@ #define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100)) +#define MTK_FE_IRQ_SHARED 0 +#define MTK_FE_IRQ_TX 0 +#define MTK_FE_IRQ_RX 1 +#define MTK_FE_IRQ_NUM (MTK_FE_IRQ_RX + 1) + struct mtk_rx_dma { unsigned int rxd1; unsigned int rxd2; @@ -951,6 +978,7 @@ enum mkt_eth_capabilities { MTK_RGMII_BIT = 0, MTK_TRGMII_BIT, MTK_SGMII_BIT, + MTK_2P5GPHY_BIT, MTK_ESW_BIT, MTK_GEPHY_BIT, MTK_MUX_BIT, @@ -971,6 +999,7 @@ enum mkt_eth_capabilities { MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT, MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, + MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT, MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, @@ -980,6 +1009,7 @@ enum mkt_eth_capabilities { MTK_ETH_PATH_GMAC1_SGMII_BIT, MTK_ETH_PATH_GMAC2_RGMII_BIT, MTK_ETH_PATH_GMAC2_SGMII_BIT, + MTK_ETH_PATH_GMAC2_2P5GPHY_BIT, MTK_ETH_PATH_GMAC2_GEPHY_BIT, MTK_ETH_PATH_GDM1_ESW_BIT, }; @@ -988,6 +1018,7 @@ enum mkt_eth_capabilities { #define MTK_RGMII BIT_ULL(MTK_RGMII_BIT) #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) +#define MTK_2P5GPHY BIT_ULL(MTK_2P5GPHY_BIT) #define MTK_ESW BIT_ULL(MTK_ESW_BIT) #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) #define MTK_MUX BIT_ULL(MTK_MUX_BIT) @@ -1010,6 +1041,8 @@ enum mkt_eth_capabilities { BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) +#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \ + BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT) #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ @@ -1021,6 +1054,7 @@ enum mkt_eth_capabilities { #define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT) #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) +#define MTK_ETH_PATH_GMAC2_2P5GPHY BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT) #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) @@ -1030,6 +1064,7 @@ enum mkt_eth_capabilities { #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) +#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY) #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) /* MUXes present on SoCs */ @@ -1049,6 +1084,10 @@ enum mkt_eth_capabilities { (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \ MTK_SHARED_SGMII) +/* 2: GMAC2 -> 2P5GPHY */ +#define MTK_MUX_GMAC2_TO_2P5GPHY \ + (MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA) + /* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) @@ -1084,8 +1123,9 @@ enum mkt_eth_capabilities { MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_RSTCTRL_PPE1 | MTK_SRAM) -#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_QDMA | \ - MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) +#define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \ + MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \ + MTK_RSTCTRL_PPE2 | MTK_SRAM) struct mtk_tx_dma_desc_info { dma_addr_t addr; @@ -1145,7 +1185,7 @@ struct mtk_reg_map { }; /* struct mtk_eth_data - This is the structure holding all differences - * among various plaforms + * among various platforms * @reg_map Soc register map. * @ana_rgc3: The offset for register ANA_RGC3 related to * sgmiisys syscon @@ -1205,8 +1245,9 @@ struct mtk_soc_data { /* struct mtk_eth - This is the main datasructure for holding the state * of the driver * @dev: The device pointer - * @dev: The device pointer used for dma mapping/alloc + * @dma_dev: The device pointer used for dma mapping/alloc * @base: The mapped register i/o base + * @sram_pool: Pointer to SRAM pool used for DMA descriptor rings * @page_lock: Make sure that register operations are atomic * @tx_irq__lock: Make sure that IRQ register operations are atomic * @rx_irq__lock: Make sure that IRQ register operations are atomic @@ -1245,21 +1286,21 @@ struct mtk_soc_data { * @mii_bus: If there is a bus we need to create an instance for it * @pending_work: The workqueue used to reset the dma ring * @state: Initialization and runtime state of the device - * @soc: Holding specific data among vaious SoCs + * @soc: Holding specific data among various SoCs */ struct mtk_eth { struct device *dev; struct device *dma_dev; void __iomem *base; - void *sram_base; + struct gen_pool *sram_pool; spinlock_t page_lock; spinlock_t tx_irq_lock; spinlock_t rx_irq_lock; struct net_device *dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; struct mtk_mac *mac[MTK_MAX_DEVS]; - int irq[3]; + int irq[MTK_FE_IRQ_NUM]; u32 msg_enable; unsigned long sysclk; struct regmap *ethsys; @@ -1437,6 +1478,23 @@ static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) return MTK_FOE_IB2_MULTICAST; } +static inline bool mtk_interface_mode_is_xgmii(struct mtk_eth *eth, + phy_interface_t interface) +{ + if (!mtk_is_netsys_v3_or_greater(eth)) + return false; + + switch (interface) { + case PHY_INTERFACE_MODE_INTERNAL: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_5GBASER: + return true; + default: + return false; + } +} + /* read the hardware status register */ void mtk_stats_update_mac(struct mtk_mac *mac); @@ -1445,6 +1503,7 @@ u32 mtk_r32(struct mtk_eth *eth, unsigned reg); u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned int reg); int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); +int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c index b175119a6a7d..b83886a41121 100644 --- a/drivers/net/ethernet/mediatek/mtk_star_emac.c +++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c @@ -1463,6 +1463,8 @@ static __maybe_unused int mtk_star_suspend(struct device *dev) if (netif_running(ndev)) mtk_star_disable(ndev); + netif_device_detach(ndev); + clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks); return 0; @@ -1487,6 +1489,8 @@ static __maybe_unused int mtk_star_resume(struct device *dev) clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks); } + netif_device_attach(ndev); + return ret; } diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c index e212a4ba9275..73c26fcfd85e 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c @@ -1318,26 +1318,14 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, static int mtk_wed_rro_alloc(struct mtk_wed_device *dev) { - struct reserved_mem *rmem; - struct device_node *np; - int index; + struct resource res; + int ret; - index = of_property_match_string(dev->hw->node, "memory-region-names", - "wo-dlm"); - if (index < 0) - return index; - - np = of_parse_phandle(dev->hw->node, "memory-region", index); - if (!np) - return -ENODEV; - - rmem = of_reserved_mem_lookup(np); - of_node_put(np); - - if (!rmem) - return -ENODEV; + ret = of_reserved_mem_region_to_resource_byname(dev->hw->node, "wo-dlm", &res); + if (ret) + return ret; - dev->rro.miod_phys = rmem->base; + dev->rro.miod_phys = res.start; dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys; return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring, @@ -2000,7 +1988,7 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) if (mtk_wed_is_v3_or_greater(dev->hw)) wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_TKID_ALI_EN); - /* initail tx interrupt trigger */ + /* initial tx interrupt trigger */ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR | @@ -2011,7 +1999,7 @@ mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG, dev->wlan.tx_tbit[1])); - /* initail txfree interrupt trigger */ + /* initial txfree interrupt trigger */ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE, MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN | MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR | diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c index c06e5ad18b01..fa6b21603416 100644 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c @@ -234,27 +234,23 @@ int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, } static int -mtk_wed_get_memory_region(struct mtk_wed_hw *hw, int index, +mtk_wed_get_memory_region(struct mtk_wed_hw *hw, const char *name, struct mtk_wed_wo_memory_region *region) { - struct reserved_mem *rmem; - struct device_node *np; - - np = of_parse_phandle(hw->node, "memory-region", index); - if (!np) - return -ENODEV; - - rmem = of_reserved_mem_lookup(np); - of_node_put(np); + struct resource res; + int ret; - if (!rmem) - return -ENODEV; + ret = of_reserved_mem_region_to_resource_byname(hw->node, name, &res); + if (ret) + return 0; - region->phy_addr = rmem->base; - region->size = rmem->size; - region->addr = devm_ioremap(hw->dev, region->phy_addr, region->size); + region->phy_addr = res.start; + region->size = resource_size(&res); + region->addr = devm_ioremap_resource(hw->dev, &res); + if (IS_ERR(region->addr)) + return PTR_ERR(region->addr); - return !region->addr ? -EINVAL : 0; + return 0; } static int @@ -319,13 +315,7 @@ mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) /* load firmware region metadata */ for (i = 0; i < ARRAY_SIZE(mem_region); i++) { - int index = of_property_match_string(wo->hw->node, - "memory-region-names", - mem_region[i].name); - if (index < 0) - continue; - - ret = mtk_wed_get_memory_region(wo->hw, index, &mem_region[i]); + ret = mtk_wed_get_memory_region(wo->hw, mem_region[i].name, &mem_region[i]); if (ret) return ret; } |