--- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig @@ -1,6 +1,6 @@ config NET_VENDOR_MEDIATEK bool "MediaTek ethernet driver" - depends on ARCH_MEDIATEK + depends on ARCH_MEDIATEK || RALINK ---help--- If you have a Mediatek SoC with ethernet, say Y. --- a/drivers/net/ethernet/mediatek/Makefile +++ b/drivers/net/ethernet/mediatek/Makefile @@ -2,4 +2,5 @@ # Makefile for the Mediatek SoCs built-in ethernet macs # -obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o +obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o mtk_sgmii.o \ + mtk_eth_path.o --- /dev/null +++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2018 Sean Wang + */ + +#include +#include + +#include "mtk_eth_soc.h" + +struct mtk_eth_muxc { + int (*set_path)(struct mtk_eth *eth, int path); +}; + +static const char * const mtk_eth_mux_name[] = { + "mux_gdm1_to_gmac1_esw", "mux_gmac2_gmac0_to_gephy", + "mux_u3_gmac2_to_qphy", "mux_gmac1_gmac2_to_sgmii_rgmii", + "mux_gmac12_to_gephy_sgmii", +}; + +static const char * const mtk_eth_path_name[] = { + "gmac1_rgmii", "gmac1_trgmii", "gmac1_sgmii", "gmac2_rgmii", + "gmac2_sgmii", "gmac2_gephy", "gdm1_esw", +}; + +static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path) +{ + u32 val, mask, set; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC1_SGMII: + mask = ~(u32)MTK_MUX_TO_ESW; + set = 0; + break; + case MTK_ETH_PATH_GDM1_ESW: + mask = ~(u32)MTK_MUX_TO_ESW; + set = MTK_MUX_TO_ESW; + break; + default: + updated = false; + break; + }; + + if (updated) { + val = mtk_r32(eth, MTK_MAC_MISC); + val = (val & mask) | set; + mtk_w32(eth, val, MTK_MAC_MISC); + } + + dev_info(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name[path], __func__, updated); + + return 0; +} + +static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) +{ + unsigned int val = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC2_GEPHY: + val = ~(u32)GEPHY_MAC_SEL; + break; + default: + updated = false; + break; + } + + if (updated) + regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val); + + dev_info(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name[path], __func__, updated); + + return 0; +} + +static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) +{ + unsigned int val = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC2_SGMII: + val = CO_QPHY_SEL; + break; + default: + updated = false; + break; + } + + if (updated) + regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); + + dev_info(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name[path], __func__, updated); + + return 0; +} + +static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) +{ + unsigned int val = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC1_SGMII: + val = SYSCFG0_SGMII_GMAC1; + break; + case MTK_ETH_PATH_GMAC2_SGMII: + val = SYSCFG0_SGMII_GMAC2; + break; + case MTK_ETH_PATH_GMAC1_RGMII: + case MTK_ETH_PATH_GMAC2_RGMII: + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + val &= SYSCFG0_SGMII_MASK; + + if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) || + (path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2)) + val = 0; + else + updated = false; + break; + default: + updated = false; + break; + }; + + if (updated) + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, val); + + dev_info(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name[path], __func__, updated); + + return 0; +} + +static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) +{ + unsigned int val = 0; + bool updated = true; + + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + + switch (path) { + case MTK_ETH_PATH_GMAC1_SGMII: + val |= SYSCFG0_SGMII_GMAC1_V2; + break; + case MTK_ETH_PATH_GMAC2_GEPHY: + val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; + break; + case MTK_ETH_PATH_GMAC2_SGMII: + val |= SYSCFG0_SGMII_GMAC2_V2; + break; + default: + updated = false; + }; + + if (updated) + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, val); + + if (!updated) + dev_info(eth->dev, "path %s no needs updatiion in %s\n", + mtk_eth_path_name[path], __func__); + + dev_info(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name[path], __func__, updated); + + return 0; +} + +static const struct mtk_eth_muxc mtk_eth_muxc[] = { + { .set_path = set_mux_gdm1_to_gmac1_esw, }, + { .set_path = set_mux_gmac2_gmac0_to_gephy, }, + { .set_path = set_mux_u3_gmac2_to_qphy, }, + { .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, }, + { .set_path = set_mux_gmac12_to_gephy_sgmii, } +}; + +static int mtk_eth_mux_setup(struct mtk_eth *eth, int path) +{ + int i, err = 0; + + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_PATH_BIT(path))) { + dev_info(eth->dev, "path %s isn't support on the SoC\n", + mtk_eth_path_name[path]); + return -EINVAL; + } + + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX)) + return 0; + + /* Setup MUX in path fabric */ + for (i = 0; i < MTK_ETH_MUX_MAX; i++) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_MUX_BIT(i))) { + err = mtk_eth_muxc[i].set_path(eth, path); + if (err) + goto out; + } else { + dev_info(eth->dev, "mux %s isn't present on the SoC\n", + mtk_eth_mux_name[i]); + } + } + +out: + return err; +} + +static int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) +{ + unsigned int val = 0; + int sid, err, path; + + path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : + MTK_ETH_PATH_GMAC2_SGMII; + + /* Setup proper MUXes along the path */ + err = mtk_eth_mux_setup(eth, path); + if (err) + return err; + + /* The path GMAC to SGMII will be enabled once the SGMIISYS is being + * setup done. + */ + regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); + + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, ~(u32)SYSCFG0_SGMII_MASK); + + /* Decide how GMAC and SGMIISYS be mapped */ + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac_id; + + /* Setup SGMIISYS with the determined property */ + if (MTK_HAS_FLAGS(eth->sgmii->flags[sid], MTK_SGMII_PHYSPEED_AN)) + err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); + else + err = mtk_sgmii_setup_mode_force(eth->sgmii, sid); + + if (err) + return err; + + regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, + SYSCFG0_SGMII_MASK, val); + + return 0; +} + +static int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) +{ + int err, path = 0; + + if (mac_id == 1) + path = MTK_ETH_PATH_GMAC2_GEPHY; + + if (!path) + return -EINVAL; + + /* Setup proper MUXes along the path */ + err = mtk_eth_mux_setup(eth, path); + if (err) + return err; + + return 0; +} + +static int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) +{ + int err, path; + + path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : + MTK_ETH_PATH_GMAC2_RGMII; + + /* Setup proper MUXes along the path */ + err = mtk_eth_mux_setup(eth, path); + if (err) + return err; + + return 0; +} + +int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode) +{ + int err; + + switch (phymode) { + case PHY_INTERFACE_MODE_TRGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_REVMII: + case PHY_INTERFACE_MODE_RMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_RGMII)) { + err = mtk_gmac_rgmii_path_setup(eth, mac_id); + if (err) + return err; + } + break; + case PHY_INTERFACE_MODE_SGMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + err = mtk_gmac_sgmii_path_setup(eth, mac_id); + if (err) + return err; + } + break; + case PHY_INTERFACE_MODE_GMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_GEPHY)) { + err = mtk_gmac_gephy_path_setup(eth, mac_id); + if (err) + return err; + } + break; + default: + break; + } + + return 0; +} --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "mtk_eth_soc.h" @@ -54,8 +55,10 @@ static const struct mtk_ethtool_stats { }; static const char * const mtk_clks_source_name[] = { - "ethif", "esw", "gp0", "gp1", "gp2", "trgpll", "sgmii_tx250m", - "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" + "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", + "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "eth2pll", }; void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) @@ -84,8 +87,8 @@ static int mtk_mdio_busy_wait(struct mtk return -1; } -static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, - u32 phy_register, u32 write_data) +u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, + u32 phy_register, u32 write_data) { if (mtk_mdio_busy_wait(eth)) return -1; @@ -103,7 +106,7 @@ static u32 _mtk_mdio_write(struct mtk_et return 0; } -static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) +u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) { u32 d; @@ -123,6 +126,34 @@ static u32 _mtk_mdio_read(struct mtk_eth return d; } +u32 mtk_cl45_ind_read(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 *data) +{ + mutex_lock(ð->mii_bus->mdio_lock); + + _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); + _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); + _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); + *data = _mtk_mdio_read(eth, port, MII_MMD_ADDR_DATA_REG); + + mutex_unlock(ð->mii_bus->mdio_lock); + + return 0; +} + +u32 mtk_cl45_ind_write(struct mtk_eth *eth, u32 port, u32 devad, u32 reg, u32 data) +{ + mutex_lock(ð->mii_bus->mdio_lock); + + _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, devad); + _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, reg); + _mtk_mdio_write(eth, port, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad); + _mtk_mdio_write(eth, port, MII_MMD_ADDR_DATA_REG, data); + + mutex_unlock(ð->mii_bus->mdio_lock); + + return 0; +} + static int mtk_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) { @@ -165,51 +196,12 @@ static void mtk_gmac0_rgmii_adjust(struc mtk_w32(eth, val, TRGMII_TCK_CTRL); } -static void mtk_gmac_sgmii_hw_setup(struct mtk_eth *eth, int mac_id) -{ - u32 val; - - /* Setup the link timer and QPHY power up inside SGMIISYS */ - regmap_write(eth->sgmiisys, SGMSYS_PCS_LINK_TIMER, - SGMII_LINK_TIMER_DEFAULT); - - regmap_read(eth->sgmiisys, SGMSYS_SGMII_MODE, &val); - val |= SGMII_REMOTE_FAULT_DIS; - regmap_write(eth->sgmiisys, SGMSYS_SGMII_MODE, val); - - regmap_read(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, &val); - val |= SGMII_AN_RESTART; - regmap_write(eth->sgmiisys, SGMSYS_PCS_CONTROL_1, val); - - regmap_read(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, &val); - val &= ~SGMII_PHYA_PWD; - regmap_write(eth->sgmiisys, SGMSYS_QPHY_PWR_STATE_CTRL, val); - - /* Determine MUX for which GMAC uses the SGMII interface */ - if (MTK_HAS_CAPS(eth->soc->caps, MTK_DUAL_GMAC_SHARED_SGMII)) { - regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); - val &= ~SYSCFG0_SGMII_MASK; - val |= !mac_id ? SYSCFG0_SGMII_GMAC1 : SYSCFG0_SGMII_GMAC2; - regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); - - dev_info(eth->dev, "setup shared sgmii for gmac=%d\n", - mac_id); - } - - /* Setup the GMAC1 going through SGMII path when SoC also support - * ESW on GMAC1 - */ - if (MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_ESW | MTK_GMAC1_SGMII) && - !mac_id) { - mtk_w32(eth, 0, MTK_MAC_MISC); - dev_info(eth->dev, "setup gmac1 going through sgmii"); - } -} - static void mtk_phy_link_adjust(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; u16 lcl_adv = 0, rmt_adv = 0; + u32 lcl_eee = 0, rmt_eee = 0; u8 flowctrl; u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | @@ -229,7 +221,7 @@ static void mtk_phy_link_adjust(struct n }; if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && - !mac->id && !mac->trgmii) + !mac->id && !mac->trgmii) mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed); if (dev->phydev->link) @@ -259,7 +251,16 @@ static void mtk_phy_link_adjust(struct n flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); } + /*EEE capability*/ + mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &lcl_eee); + mtk_cl45_ind_read(eth, 0, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &rmt_eee); + + if ((lcl_eee & rmt_eee & MDIO_EEE_1000T) == MDIO_EEE_1000T) + mcr |= MAC_MCR_MDIO_EEE_1000T; + if ((lcl_eee & rmt_eee & MDIO_EEE_100TX) == MDIO_EEE_100TX) + mcr |= MAC_MCR_MDIO_EEE_100TX; + /*Setup MCR*/ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); if (dev->phydev->link) @@ -290,10 +291,10 @@ static int mtk_phy_connect_node(struct m return -ENODEV; } - dev_info(eth->dev, - "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", - mac->id, phydev_name(phydev), phydev->phy_id, - phydev->drv->name); + dev_info(eth->dev, + "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", + mac->id, phydev_name(phydev), phydev->phy_id, + phydev->drv->name); return 0; } @@ -304,6 +305,7 @@ static int mtk_phy_connect(struct net_de struct mtk_eth *eth; struct device_node *np; u32 val; + int err; eth = mac->hw; np = of_parse_phandle(mac->of_node, "phy-handle", 0); @@ -313,6 +315,10 @@ static int mtk_phy_connect(struct net_de if (!np) return -ENODEV; + err = mtk_setup_hw_path(eth, mac->id, of_get_phy_mode(np)); + if (err) + goto err_phy; + mac->ge_mode = 0; switch (of_get_phy_mode(np)) { case PHY_INTERFACE_MODE_TRGMII: @@ -323,10 +329,9 @@ static int mtk_phy_connect(struct net_de case PHY_INTERFACE_MODE_RGMII: break; case PHY_INTERFACE_MODE_SGMII: - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) - mtk_gmac_sgmii_hw_setup(eth, mac->id); break; case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: mac->ge_mode = 1; break; case PHY_INTERFACE_MODE_REVMII: @@ -355,7 +360,7 @@ static int mtk_phy_connect(struct net_de dev->phydev->speed = 0; dev->phydev->duplex = 0; - if (of_phy_is_fixed_link(mac->of_node)) + if (!strncmp(dev->phydev->drv->name, "Generic", 7)) dev->phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; @@ -535,37 +540,37 @@ static void mtk_stats_update(struct mtk_ } static void mtk_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *storage) + struct rtnl_link_stats64 *storage) { - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_hw_stats *hw_stats = mac->hw_stats; - unsigned int start; - - if (netif_running(dev) && netif_device_present(dev)) { - if (spin_trylock_bh(&hw_stats->stats_lock)) { - mtk_stats_update_mac(mac); - spin_unlock_bh(&hw_stats->stats_lock); - } - } - - do { - start = u64_stats_fetch_begin_irq(&hw_stats->syncp); - storage->rx_packets = hw_stats->rx_packets; - storage->tx_packets = hw_stats->tx_packets; - storage->rx_bytes = hw_stats->rx_bytes; - storage->tx_bytes = hw_stats->tx_bytes; - storage->collisions = hw_stats->tx_collisions; - storage->rx_length_errors = hw_stats->rx_short_errors + - hw_stats->rx_long_errors; - storage->rx_over_errors = hw_stats->rx_overflow; - storage->rx_crc_errors = hw_stats->rx_fcs_errors; - storage->rx_errors = hw_stats->rx_checksum_errors; - storage->tx_aborted_errors = hw_stats->tx_skip; - } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); - - storage->tx_errors = dev->stats.tx_errors; - storage->rx_dropped = dev->stats.rx_dropped; - storage->tx_dropped = dev->stats.tx_dropped; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; + unsigned int start; + + if (netif_running(dev) && netif_device_present(dev)) { + if (spin_trylock_bh(&hw_stats->stats_lock)) { + mtk_stats_update_mac(mac); + spin_unlock_bh(&hw_stats->stats_lock); + } + } + + do { + start = u64_stats_fetch_begin_irq(&hw_stats->syncp); + storage->rx_packets = hw_stats->rx_packets; + storage->tx_packets = hw_stats->tx_packets; + storage->rx_bytes = hw_stats->rx_bytes; + storage->tx_bytes = hw_stats->tx_bytes; + storage->collisions = hw_stats->tx_collisions; + storage->rx_length_errors = hw_stats->rx_short_errors + + hw_stats->rx_long_errors; + storage->rx_over_errors = hw_stats->rx_overflow; + storage->rx_crc_errors = hw_stats->rx_fcs_errors; + storage->rx_errors = hw_stats->rx_checksum_errors; + storage->tx_aborted_errors = hw_stats->tx_skip; + } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); + + storage->tx_errors = dev->stats.tx_errors; + storage->rx_dropped = dev->stats.rx_dropped; + storage->tx_dropped = dev->stats.tx_dropped; } static inline int mtk_max_frag_size(int mtu) @@ -605,10 +610,10 @@ static int mtk_init_fq_dma(struct mtk_et dma_addr_t dma_addr; int i; - eth->scratch_ring = dma_zalloc_coherent(eth->dev, - cnt * sizeof(struct mtk_tx_dma), - ð->phy_scratch_ring, - GFP_ATOMIC); + eth->scratch_ring = dma_alloc_coherent(eth->dev, + cnt * sizeof(struct mtk_tx_dma), + ð->phy_scratch_ring, + GFP_ATOMIC | __GFP_ZERO); if (unlikely(!eth->scratch_ring)) return -ENOMEM; @@ -623,6 +628,7 @@ static int mtk_init_fq_dma(struct mtk_et if (unlikely(dma_mapping_error(eth->dev, dma_addr))) return -ENOMEM; + memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt); phy_ring_tail = eth->phy_scratch_ring + (sizeof(struct mtk_tx_dma) * (cnt - 1)); @@ -673,7 +679,7 @@ static void mtk_tx_unmap(struct mtk_eth } tx_buf->flags = 0; if (tx_buf->skb && - (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) + (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) dev_kfree_skb_any(tx_buf->skb); tx_buf->skb = NULL; } @@ -689,6 +695,7 @@ static int mtk_tx_map(struct sk_buff *sk unsigned int nr_frags; int i, n_desc = 1; u32 txd4 = 0, fport; + u32 qid = 0; itxd = ring->next_free; if (itxd == ring->last_free) @@ -708,9 +715,10 @@ static int mtk_tx_map(struct sk_buff *sk if (skb->ip_summed == CHECKSUM_PARTIAL) txd4 |= TX_DMA_CHKSUM; - /* VLAN header offload */ - if (skb_vlan_tag_present(skb)) - txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); +#if defined(CONFIG_NET_MEDIATEK_HW_QOS) + qid = skb->mark & (MTK_QDMA_TX_MASK); + qid += (!mac->id) ? (MTK_QDMA_TX_MASK + 1) : 0; +#endif mapped_addr = dma_map_single(eth->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); @@ -727,6 +735,7 @@ static int mtk_tx_map(struct sk_buff *sk /* TX SG offload */ txd = itxd; nr_frags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; unsigned int offset = 0; @@ -753,10 +762,10 @@ static int mtk_tx_map(struct sk_buff *sk last_frag = true; WRITE_ONCE(txd->txd1, mapped_addr); - WRITE_ONCE(txd->txd3, (TX_DMA_SWC | + WRITE_ONCE(txd->txd3, (TX_DMA_SWC | QID_LOW_BITS(qid) | TX_DMA_PLEN0(frag_map_size) | last_frag * TX_DMA_LS0)); - WRITE_ONCE(txd->txd4, fport); + WRITE_ONCE(txd->txd4, fport | QID_HIGH_BITS(qid)); tx_buf = mtk_desc_to_tx_buf(ring, txd); memset(tx_buf, 0, sizeof(*tx_buf)); @@ -775,9 +784,9 @@ static int mtk_tx_map(struct sk_buff *sk /* store skb to cleanup */ itx_buf->skb = skb; - WRITE_ONCE(itxd->txd4, txd4); WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | - (!nr_frags * TX_DMA_LS0))); + (!nr_frags * TX_DMA_LS0)) | QID_LOW_BITS(qid)); + WRITE_ONCE(itxd->txd4, txd4 | QID_HIGH_BITS(qid)); netdev_sent_queue(dev, skb->len); skb_tx_timestamp(skb); @@ -922,7 +931,7 @@ drop: return NETDEV_TX_OK; } -static struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) +struct mtk_rx_ring *mtk_get_rx_ring(struct mtk_eth *eth) { int i; struct mtk_rx_ring *ring; @@ -991,10 +1000,24 @@ static int mtk_poll_rx(struct napi_struc break; /* find out which mac the packet come from. values start at 1 */ +#if defined(CONFIG_NET_DSA) + mac = (trxd.rxd4 >> 22) & 0x1; + mac = (mac + 1) % 2; +#else mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & - RX_DMA_FPORT_MASK; - mac--; - + RX_DMA_FPORT_MASK; + /* From QDMA(5). This is a external interface case of HWNAT. + * When the incoming frame comes from an external interface + * rather than GMAC1/GMAC2, HWNAT driver sends the original + * frame to PPE via PPD(ping pong device) for HWNAT RX + * frame learning. After learning, PPE transmit the + * original frame back to PPD again to run SW NAT path. + */ + if (mac == 5) + mac = 0; + else + mac--; +#endif if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || !eth->netdev[mac])) goto release_desc; @@ -1044,6 +1067,7 @@ static int mtk_poll_rx(struct napi_struc RX_DMA_VID(trxd.rxd3)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), RX_DMA_VID(trxd.rxd3)); + skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); @@ -1128,7 +1152,7 @@ static int mtk_poll_tx(struct mtk_eth *e } if (mtk_queue_stopped(eth) && - (atomic_read(&ring->free_count) > ring->thresh)) + (atomic_read(&ring->free_count) > ring->thresh)) mtk_wake_queue(eth); return total; @@ -1220,11 +1244,14 @@ static int mtk_tx_alloc(struct mtk_eth * if (!ring->buf) goto no_tx_mem; - ring->dma = dma_zalloc_coherent(eth->dev, MTK_DMA_SIZE * sz, - &ring->phys, GFP_ATOMIC); + ring->dma = dma_alloc_coherent(eth->dev, + MTK_DMA_SIZE * sz, + &ring->phys, + GFP_ATOMIC | __GFP_ZERO); if (!ring->dma) goto no_tx_mem; + memset(ring->dma, 0, MTK_DMA_SIZE * sz); for (i = 0; i < MTK_DMA_SIZE; i++) { int next = (i + 1) % MTK_DMA_SIZE; u32 next_ptr = ring->phys + next * sz; @@ -1317,9 +1344,10 @@ static int mtk_rx_alloc(struct mtk_eth * return -ENOMEM; } - ring->dma = dma_zalloc_coherent(eth->dev, - rx_dma_size * sizeof(*ring->dma), - &ring->phys, GFP_ATOMIC); + ring->dma = dma_alloc_coherent(eth->dev, + rx_dma_size * sizeof(*ring->dma), + &ring->phys, + GFP_ATOMIC | __GFP_ZERO); if (!ring->dma) return -ENOMEM; @@ -1516,8 +1544,8 @@ static int mtk_hwlro_add_ipaddr(struct n int hwlro_idx; if ((fsp->flow_type != TCP_V4_FLOW) || - (!fsp->h_u.tcp_ip4_spec.ip4dst) || - (fsp->location > 1)) + (!fsp->h_u.tcp_ip4_spec.ip4dst) || + (fsp->location > 1)) return -EINVAL; mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst); @@ -1744,6 +1772,34 @@ static void mtk_tx_timeout(struct net_de schedule_work(ð->pending_work); } +static irqreturn_t mtk_handle_irq_tx_rx(int irq, void *_eth) +{ + struct mtk_eth *eth = _eth; + u32 tx_status, rx_status; + + tx_status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + + if (tx_status & MTK_TX_DONE_INT) { + if (likely(napi_schedule_prep(ð->tx_napi))) { + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); + __napi_schedule(ð->tx_napi); + } + mtk_w32(eth, tx_status, MTK_QMTK_INT_STATUS); + } + + rx_status = mtk_r32(eth, MTK_PDMA_INT_STATUS); + + if (rx_status & MTK_RX_DONE_INT) { + if (likely(napi_schedule_prep(ð->rx_napi))) { + mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); + __napi_schedule(ð->rx_napi); + } + mtk_w32(eth, rx_status, MTK_PDMA_INT_STATUS); + } + + return IRQ_HANDLED; +} + static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) { struct mtk_eth *eth = _eth; @@ -1784,8 +1840,8 @@ static void mtk_poll_controller(struct n static int mtk_start_dma(struct mtk_eth *eth) { - u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; int err; + u32 rx_2b_offet = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; err = mtk_dma_init(eth); if (err) { @@ -1801,7 +1857,7 @@ static int mtk_start_dma(struct mtk_eth MTK_QDMA_GLO_CFG); mtk_w32(eth, - MTK_RX_DMA_EN | rx_2b_offset | + MTK_RX_DMA_EN | rx_2b_offet | MTK_RX_BT_32DWORDS | MTK_MULTI_EN, MTK_PDMA_GLO_CFG); @@ -1814,7 +1870,7 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; /* we run 2 netdevs on the same dma ring so we only bring it up once */ - if (!refcount_read(ð->dma_refcnt)) { + if (!atomic_read(ð->dma_refcnt)) { int err = mtk_start_dma(eth); if (err) @@ -1824,10 +1880,8 @@ static int mtk_open(struct net_device *d napi_enable(ð->rx_napi); mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); - refcount_set(ð->dma_refcnt, 1); } - else - refcount_inc(ð->dma_refcnt); + atomic_inc(ð->dma_refcnt); phy_start(dev->phydev); netif_start_queue(dev); @@ -1867,7 +1921,7 @@ static int mtk_stop(struct net_device *d phy_stop(dev->phydev); /* only shutdown DMA if this is the last user */ - if (!refcount_dec_and_test(ð->dma_refcnt)) + if (!atomic_dec_and_test(ð->dma_refcnt)) return 0; mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); @@ -1973,14 +2027,16 @@ static int mtk_hw_init(struct mtk_eth *e val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); - /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + /* Disable RX VLan Offloading */ + mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); + +#if defined(CONFIG_NET_DSA) + mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL); +#endif - /* enable interrupt delay for RX */ - mtk_w32(eth, MTK_PDMA_DELAY_RX_DELAY, MTK_PDMA_DELAY_INT); + mtk_w32(eth, 0x8f0f8f0f, MTK_PDMA_DELAY_INT); + mtk_w32(eth, 0x8f0f8f0f, MTK_QDMA_DELAY_INT); - /* disable delay and normal interrupt */ - mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); mtk_tx_irq_disable(eth, ~0); mtk_rx_irq_disable(eth, ~0); mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); @@ -2172,27 +2228,27 @@ static int mtk_cleanup(struct mtk_eth *e } static int mtk_get_link_ksettings(struct net_device *ndev, - struct ethtool_link_ksettings *cmd) + struct ethtool_link_ksettings *cmd) { - struct mtk_mac *mac = netdev_priv(ndev); + struct mtk_mac *mac = netdev_priv(ndev); - if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) - return -EBUSY; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; - phy_ethtool_ksettings_get(ndev->phydev, cmd); + phy_ethtool_ksettings_get(ndev->phydev, cmd); - return 0; + return 0; } static int mtk_set_link_ksettings(struct net_device *ndev, - const struct ethtool_link_ksettings *cmd) + const struct ethtool_link_ksettings *cmd) { - struct mtk_mac *mac = netdev_priv(ndev); + struct mtk_mac *mac = netdev_priv(ndev); - if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) - return -EBUSY; + if (unlikely(test_bit(MTK_RESETTING, &mac->hw->state))) + return -EBUSY; - return phy_ethtool_ksettings_set(ndev->phydev, cmd); + return phy_ethtool_ksettings_set(ndev->phydev, cmd); } static void mtk_get_drvinfo(struct net_device *dev, @@ -2355,8 +2411,8 @@ static int mtk_set_rxnfc(struct net_devi } static const struct ethtool_ops mtk_ethtool_ops = { - .get_link_ksettings = mtk_get_link_ksettings, - .set_link_ksettings = mtk_set_link_ksettings, + .get_link_ksettings = mtk_get_link_ksettings, + .set_link_ksettings = mtk_set_link_ksettings, .get_drvinfo = mtk_get_drvinfo, .get_msglevel = mtk_get_msglevel, .set_msglevel = mtk_set_msglevel, @@ -2366,7 +2422,7 @@ static const struct ethtool_ops mtk_etht .get_sset_count = mtk_get_sset_count, .get_ethtool_stats = mtk_get_ethtool_stats, .get_rxnfc = mtk_get_rxnfc, - .set_rxnfc = mtk_set_rxnfc, + .set_rxnfc = mtk_set_rxnfc, }; static const struct net_device_ops mtk_netdev_ops = { @@ -2463,6 +2519,7 @@ static int mtk_probe(struct platform_dev { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct device_node *mac_np; + const struct of_device_id *match; struct mtk_eth *eth; int err; int i; @@ -2471,7 +2528,8 @@ static int mtk_probe(struct platform_dev if (!eth) return -ENOMEM; - eth->soc = of_device_get_match_data(&pdev->dev); + match = of_match_device(of_mtk_match, &pdev->dev); + eth->soc = (struct mtk_soc_data *)match->data; eth->dev = &pdev->dev; eth->base = devm_ioremap_resource(&pdev->dev, res); @@ -2489,26 +2547,37 @@ static int mtk_probe(struct platform_dev return PTR_ERR(eth->ethsys); } - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { - eth->sgmiisys = - syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "mediatek,sgmiisys"); - if (IS_ERR(eth->sgmiisys)) { - dev_err(&pdev->dev, "no sgmiisys regmap found\n"); - return PTR_ERR(eth->sgmiisys); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_INFRA)) { + eth->infra = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "mediatek,infracfg"); + if (IS_ERR(eth->infra)) { + dev_info(&pdev->dev, "no ethsys regmap found\n"); + return PTR_ERR(eth->infra); } } + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), + GFP_KERNEL); + if (!eth->sgmii) + return -ENOMEM; + + err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, + eth->soc->ana_rgc3); + if (err) + return err; + } + if (eth->soc->required_pctl) { eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mediatek,pctl"); if (IS_ERR(eth->pctl)) { - dev_err(&pdev->dev, "no pctl regmap found\n"); + dev_info(&pdev->dev, "no pctl regmap found\n"); return PTR_ERR(eth->pctl); } } - for (i = 0; i < 3; i++) { + for (i = 0; i < eth->soc->irq_num; i++) { eth->irq[i] = platform_get_irq(pdev, i); if (eth->irq[i] < 0) { dev_err(&pdev->dev, "no IRQ%d resource found\n", i); @@ -2552,15 +2621,22 @@ static int mtk_probe(struct platform_dev goto err_deinit_hw; } - err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, - dev_name(eth->dev), eth); - if (err) - goto err_free_dev; + if (eth->soc->irq_num > 1) { + err = devm_request_irq(eth->dev, eth->irq[1], 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], mtk_handle_irq_rx, 0, - dev_name(eth->dev), eth); - if (err) - goto err_free_dev; + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; + } else { + err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq_tx_rx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; + } err = mtk_mdio_init(eth); if (err) @@ -2626,27 +2702,48 @@ static int mtk_remove(struct platform_de } static const struct mtk_soc_data mt2701_data = { - .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, + .caps = MT7623_CAPS | MTK_HWLRO, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, + .irq_num = 3, }; static const struct mtk_soc_data mt7622_data = { - .caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW | MTK_HWLRO, + .ana_rgc3 = 0x2028, + .caps = MT7622_CAPS | MTK_HWLRO, .required_clks = MT7622_CLKS_BITMAP, .required_pctl = false, + .irq_num = 3, }; static const struct mtk_soc_data mt7623_data = { - .caps = MTK_GMAC1_TRGMII | MTK_HWLRO, + .caps = MT7623_CAPS | MTK_HWLRO, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, + .irq_num = 3, +}; + +static const struct mtk_soc_data leopard_data = { + .ana_rgc3 = 0x128, + .caps = LEOPARD_CAPS | MTK_HWLRO, + .required_clks = LEOPARD_CLKS_BITMAP, + .required_pctl = false, + .irq_num = 3, +}; + +static const struct mtk_soc_data mt7621_data = { + .caps = MT7621_CAPS, + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, + .irq_num = 1, }; const struct of_device_id of_mtk_match[] = { { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, + { .compatible = "mediatek,mt7629-eth", .data = &leopard_data}, + { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, {}, }; MODULE_DEVICE_TABLE(of, of_mtk_match); --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -15,13 +15,17 @@ #ifndef MTK_ETH_H #define MTK_ETH_H +#include +#include +#include +#include #include #define MTK_QDMA_PAGE_SIZE 2048 #define MTK_MAX_RX_LENGTH 1536 #define MTK_TX_DMA_BUF_LEN 0x3fff -#define MTK_DMA_SIZE 256 -#define MTK_NAPI_WEIGHT 64 +#define MTK_DMA_SIZE 2048 +#define MTK_NAPI_WEIGHT 256 #define MTK_MAC_COUNT 2 #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) @@ -36,8 +40,6 @@ NETIF_MSG_TX_ERR) #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ NETIF_F_RXCSUM | \ - NETIF_F_HW_VLAN_CTAG_TX | \ - NETIF_F_HW_VLAN_CTAG_RX | \ NETIF_F_SG | NETIF_F_TSO | \ NETIF_F_TSO6 | \ NETIF_F_IPV6_CSUM) @@ -76,6 +78,9 @@ #define MTK_CDMQ_IG_CTRL 0x1400 #define MTK_CDMQ_STAG_EN BIT(0) +/* CDMP Ingress Control Register */ +#define MTK_CDMP_IG_CTRL 0x400 + /* CDMP Exgress Control Register */ #define MTK_CDMP_EG_CTRL 0x404 @@ -225,8 +230,9 @@ #define MTK_TX_DONE_INT1 BIT(1) #define MTK_TX_DONE_INT0 BIT(0) #define MTK_RX_DONE_INT MTK_RX_DONE_DLY -#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ - MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) +#define MTK_TX_DONE_DLY BIT(28) +#define MTK_TX_DONE_INT MTK_TX_DONE_DLY + /* QDMA Interrupt grouping registers */ #define MTK_QDMA_INT_GRP1 0x1a20 @@ -267,6 +273,12 @@ #define MTK_GDM1_TX_GBCNT 0x2400 #define MTK_STAT_OFFSET 0x40 +/* QDMA TX NUM */ +#define MTK_QDMA_TX_NUM 16 +#define MTK_QDMA_TX_MASK ((MTK_QDMA_TX_NUM / 2) - 1) +#define QID_LOW_BITS(x) ((x) & 0xf) +#define QID_HIGH_BITS(x) ((((x) >> 4) & 0x3) & GENMASK(21, 20)) + /* QDMA descriptor txd4 */ #define TX_DMA_CHKSUM (0x7 << 29) #define TX_DMA_TSO BIT(28) @@ -316,6 +328,8 @@ #define MAC_MCR_RX_EN BIT(13) #define MAC_MCR_BACKOFF_EN BIT(9) #define MAC_MCR_BACKPR_EN BIT(8) +#define MAC_MCR_MDIO_EEE_1000T BIT(7) +#define MAC_MCR_MDIO_EEE_100TX BIT(6) #define MAC_MCR_FORCE_RX_FC BIT(5) #define MAC_MCR_FORCE_TX_FC BIT(4) #define MAC_MCR_SPEED_1000 BIT(3) @@ -368,9 +382,11 @@ #define ETHSYS_SYSCFG0 0x14 #define SYSCFG0_GE_MASK 0x3 #define SYSCFG0_GE_MODE(x, y) (x << (12 + (y * 2))) -#define SYSCFG0_SGMII_MASK (3 << 8) -#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & GENMASK(9, 8)) -#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & GENMASK(9, 8)) +#define SYSCFG0_SGMII_MASK GENMASK(9, 8) +#define SYSCFG0_SGMII_GMAC1 ((2 << 8) & SYSCFG0_SGMII_MASK) +#define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) +#define SYSCFG0_SGMII_GMAC1_V2 BIT(9) +#define SYSCFG0_SGMII_GMAC2_V2 BIT(8) /* ethernet subsystem clock register */ #define ETHSYS_CLKCFG0 0x2c @@ -398,6 +414,16 @@ #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 #define SGMII_PHYA_PWD BIT(4) +/* Infrasys subsystem config registers */ +#define INFRA_MISC2 0x70c +#define CO_QPHY_SEL BIT(0) +#define GEPHY_MAC_SEL BIT(1) + +/*MDIO control*/ +#define MII_MMD_ACC_CTL_REG 0x0d +#define MII_MMD_ADDR_DATA_REG 0x0e +#define MMD_OP_MODE_DATA BIT(14) + struct mtk_rx_dma { unsigned int rxd1; unsigned int rxd2; @@ -462,15 +488,21 @@ enum mtk_tx_flags { */ enum mtk_clks_map { MTK_CLK_ETHIF, + MTK_CLK_SGMIITOP, MTK_CLK_ESW, MTK_CLK_GP0, MTK_CLK_GP1, MTK_CLK_GP2, + MTK_CLK_FE, MTK_CLK_TRGPLL, MTK_CLK_SGMII_TX_250M, MTK_CLK_SGMII_RX_250M, MTK_CLK_SGMII_CDR_REF, MTK_CLK_SGMII_CDR_FB, + MTK_CLK_SGMII2_TX_250M, + MTK_CLK_SGMII2_RX_250M, + MTK_CLK_SGMII2_CDR_REF, + MTK_CLK_SGMII2_CDR_FB, MTK_CLK_SGMII_CK, MTK_CLK_ETH2PLL, MTK_CLK_MAX @@ -488,6 +520,22 @@ enum mtk_clks_map { BIT(MTK_CLK_SGMII_CDR_FB) | \ BIT(MTK_CLK_SGMII_CK) | \ BIT(MTK_CLK_ETH2PLL)) +#define LEOPARD_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ + BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \ + BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \ + BIT(MTK_CLK_SGMII_TX_250M) | \ + BIT(MTK_CLK_SGMII_RX_250M) | \ + BIT(MTK_CLK_SGMII_CDR_REF) | \ + BIT(MTK_CLK_SGMII_CDR_FB) | \ + BIT(MTK_CLK_SGMII2_TX_250M) | \ + BIT(MTK_CLK_SGMII2_RX_250M) | \ + BIT(MTK_CLK_SGMII2_CDR_REF) | \ + BIT(MTK_CLK_SGMII2_CDR_FB) | \ + BIT(MTK_CLK_SGMII_CK) | \ + BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) + +#define MT7621_CLKS_BITMAP 0 + enum mtk_dev_state { MTK_HW_INIT, MTK_RESETTING @@ -557,35 +605,149 @@ struct mtk_rx_ring { u32 crx_idx_reg; }; -#define MTK_TRGMII BIT(0) -#define MTK_GMAC1_TRGMII (BIT(1) | MTK_TRGMII) -#define MTK_ESW BIT(4) -#define MTK_GMAC1_ESW (BIT(5) | MTK_ESW) -#define MTK_SGMII BIT(8) -#define MTK_GMAC1_SGMII (BIT(9) | MTK_SGMII) -#define MTK_GMAC2_SGMII (BIT(10) | MTK_SGMII) -#define MTK_DUAL_GMAC_SHARED_SGMII (BIT(11) | MTK_GMAC1_SGMII | \ - MTK_GMAC2_SGMII) +enum mtk_eth_mux { + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW, + MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, + MTK_ETH_MUX_U3_GMAC2_TO_QPHY, + MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, + MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, + MTK_ETH_MUX_MAX, +}; + +enum mtk_eth_path { + MTK_ETH_PATH_GMAC1_RGMII, + MTK_ETH_PATH_GMAC1_TRGMII, + MTK_ETH_PATH_GMAC1_SGMII, + MTK_ETH_PATH_GMAC2_RGMII, + MTK_ETH_PATH_GMAC2_SGMII, + MTK_ETH_PATH_GMAC2_GEPHY, + MTK_ETH_PATH_GDM1_ESW, + MTK_ETH_PATH_MAX, +}; + +/* Capability for function group */ +#define MTK_RGMII BIT(0) +#define MTK_TRGMII BIT(1) +#define MTK_SGMII BIT(2) +#define MTK_ESW BIT(3) +#define MTK_GEPHY BIT(4) +#define MTK_MUX BIT(5) +#define MTK_INFRA BIT(6) +#define MTK_SHARED_SGMII BIT(7) + +/* Capability for features on SoCs */ +#define MTK_PATH_BIT(x) BIT((x) + 10) + +#define MTK_GMAC1_RGMII \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_RGMII) | MTK_RGMII) + +#define MTK_GMAC1_TRGMII \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_TRGMII) | MTK_TRGMII) + +#define MTK_GMAC1_SGMII \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC1_SGMII) | MTK_SGMII) + +#define MTK_GMAC2_RGMII \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_RGMII) | MTK_RGMII) + +#define MTK_GMAC2_SGMII \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_SGMII) | MTK_SGMII) + +#define MTK_GMAC2_GEPHY \ + (MTK_PATH_BIT(MTK_ETH_PATH_GMAC2_GEPHY) | MTK_GEPHY) + +#define MTK_GDM1_ESW \ + (MTK_PATH_BIT(MTK_ETH_PATH_GDM1_ESW) | MTK_ESW) + +#define MTK_MUX_BIT(x) BIT((x) + 20) + +/* Capability for MUXes present on SoCs */ +/* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ +#define MTK_MUX_GDM1_TO_GMAC1_ESW \ + (MTK_MUX_BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW) | MTK_MUX) + +/* 0: GMAC2 -> GEPHY, 1: GMAC0 -> GePHY */ +#define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \ + (MTK_MUX_BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY) | MTK_MUX | MTK_INFRA) + +/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */ +#define MTK_MUX_U3_GMAC2_TO_QPHY \ + (MTK_MUX_BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY) | MTK_MUX | MTK_INFRA) + +/* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */ +#define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ + (MTK_MUX_BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) | MTK_MUX | \ + MTK_SHARED_SGMII) + +/* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ +#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_MUX_BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII) | MTK_MUX) + #define MTK_HWLRO BIT(12) + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) +#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \ + MTK_GMAC2_SGMII | MTK_GDM1_ESW | \ + MTK_MUX_GDM1_TO_GMAC1_ESW | \ + MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII) + +#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) + +#define LEOPARD_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ + MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \ + MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \ + MTK_MUX_U3_GMAC2_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII) + +#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII) + /* struct mtk_eth_data - This is the structure holding all differences * among various plaforms + * @ana_rgc3: The offset for register ANA_RGC3 related to + * sgmiisys syscon * @caps Flags shown the extra capability for the SoC * @required_clks Flags shown the bitmap for required clocks on * the target SoC * @required_pctl A bool value to show whether the SoC requires * the extra setup for those pins used by GMAC. + * @irq_num total eth irq num support in target SoC */ struct mtk_soc_data { + u32 ana_rgc3; u32 caps; u32 required_clks; bool required_pctl; + u32 irq_num; }; /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 +struct mtk_eth_debug { + struct dentry *root; +}; + +#define MTK_SGMII_PHYSPEED_AN BIT(31) +#define MTK_SGMII_PHYSPEED_MASK GENMASK(0, 2) +#define MTK_SGMII_PHYSPEED_1000 BIT(0) +#define MTK_SGMII_PHYSPEED_2500 BIT(1) +#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) + +/* struct mtk_sgmii - This is the structure holding sgmii regmap and its + * characteristics + * @regmap: The register map pointing at the range used to setup + * SGMII modes + * @flags: The enum refers to which mode the sgmii wants to run on + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + */ + +struct mtk_sgmii { + struct regmap *regmap[MTK_MAX_DEVS]; + u32 flags[MTK_MAX_DEVS]; + u32 ana_rgc3; +}; + /* struct mtk_eth - This is the main datasructure for holding the state * of the driver * @dev: The device pointer @@ -601,14 +763,15 @@ struct mtk_soc_data { * @msg_enable: Ethtool msg level * @ethsys: The register map pointing at the range used to setup * MII modes - * @sgmiisys: The register map pointing at the range used to setup - * SGMII modes + * @infra: The register map pointing at the range used to setup + * SGMII and GePHY path * @pctl: The register map pointing at the range used to setup * GMAC port drive/slew values * @dma_refcnt: track how many netdevs are using the DMA engine * @tx_ring: Pointer to the memory holding info about the TX ring * @rx_ring: Pointer to the memory holding info about the RX ring - * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ring + * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX + * ring * @tx_napi: The TX NAPI struct * @rx_napi: The RX NAPI struct * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring @@ -619,13 +782,16 @@ struct mtk_soc_data { * @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 + * @debug: Holding specific data for mtk_eth_dbg usage. */ struct mtk_eth { struct device *dev; void __iomem *base; spinlock_t page_lock; + /* spin_lock for enable/disable tx irq critial section */ spinlock_t tx_irq_lock; + /* spin_lock for enable/disable rx irq critial section */ spinlock_t rx_irq_lock; struct net_device dummy_dev; struct net_device *netdev[MTK_MAX_DEVS]; @@ -634,10 +800,11 @@ struct mtk_eth { u32 msg_enable; unsigned long sysclk; struct regmap *ethsys; - struct regmap *sgmiisys; + struct regmap *infra; + struct mtk_sgmii *sgmii; struct regmap *pctl; bool hwlro; - refcount_t dma_refcnt; + atomic_t dma_refcnt; struct mtk_tx_ring tx_ring; struct mtk_rx_ring rx_ring[MTK_MAX_RX_RING_NUM]; struct mtk_rx_ring rx_ring_qdma; @@ -653,6 +820,7 @@ struct mtk_eth { unsigned long state; const struct mtk_soc_data *soc; + struct mtk_eth_debug debug; }; /* struct mtk_mac - the structure that holds the info about the MACs of the @@ -664,6 +832,7 @@ struct mtk_eth { * @hw_stats: Packet statistics counter * @trgmii Indicate if the MAC uses TRGMII connected to internal switch + * @phy_dev: The attached PHY if available */ struct mtk_mac { int id; @@ -674,6 +843,7 @@ struct mtk_mac { __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; int hwlro_ip_cnt; bool trgmii; + struct phy_device *phy_dev; }; /* the struct describing the SoC. these are declared in the soc_xyz.c files */ @@ -685,4 +855,10 @@ void mtk_stats_update_mac(struct mtk_mac void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); u32 mtk_r32(struct mtk_eth *eth, unsigned reg); +int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, + u32 ana_rgc3); +int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); +int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id); +int mtk_setup_hw_path(struct mtk_eth *eth, int mac_id, int phymode); + #endif /* MTK_ETH_H */ --- /dev/null +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2018 Sean Wang + */ + +#include +#include +#include + +#include "mtk_eth_soc.h" + +int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) +{ + struct device_node *np; + const char *str; + int i, err; + + ss->ana_rgc3 = ana_rgc3; + + for (i = 0; i < MTK_MAX_DEVS; i++) { + np = of_parse_phandle(r, "mediatek,sgmiisys", i); + if (!np) + break; + + ss->regmap[i] = syscon_node_to_regmap(np); + if (IS_ERR(ss->regmap[i])) + return PTR_ERR(ss->regmap[i]); + + err = of_property_read_string(np, "mediatek,physpeed", &str); + if (err) + return err; + + if (!strcmp(str, "2500")) + pr_info("sean debug physpeed = 2500\n"); + + if (!strcmp(str, "2500")) + ss->flags[i] |= MTK_SGMII_PHYSPEED_2500; + else if (!strcmp(str, "1000")) + ss->flags[i] |= MTK_SGMII_PHYSPEED_1000; + else if (!strcmp(str, "auto")) + ss->flags[i] |= MTK_SGMII_PHYSPEED_AN; + else + return -EINVAL; + } + + return 0; +} + +int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) +{ + unsigned int val; + + if (!ss->regmap[id]) + return -EINVAL; + + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, + SGMII_LINK_TIMER_DEFAULT); + + regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); + val |= SGMII_REMOTE_FAULT_DIS; + regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); + + regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); + val |= SGMII_AN_RESTART; + regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); + + regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); + + return 0; +} + +int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id) +{ + unsigned int val; + int mode; + + if (!ss->regmap[id]) + return -EINVAL; + + regmap_read(ss->regmap[id], ss->ana_rgc3, &val); + val &= ~GENMASK(2, 3); + mode = ss->flags[id] & MTK_SGMII_PHYSPEED_MASK; + val |= (mode == MTK_SGMII_PHYSPEED_1000) ? 0 : BIT(2); + regmap_write(ss->regmap[id], ss->ana_rgc3, val); + + /* disable SGMII AN */ + regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); + val &= ~BIT(12); + regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); + + /* SGMII force mode setting */ + val = 0x31120019; + regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); + + /* Release PHYA power down state */ + regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); + + return 0; +}