diff options
Diffstat (limited to 'drivers/net/ethernet/mediatek/mtk_eth_soc.c')
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_soc.c | 167 |
1 files changed, 91 insertions, 76 deletions
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index f9fbb3ffa3a6..c39d7f4ab1d4 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1,11 +1,5 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* * * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> @@ -54,8 +48,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) @@ -138,6 +134,31 @@ static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) return _mtk_mdio_read(eth, phy_addr, phy_reg); } +static int mt7621_gmac0_rgmii_adjust(struct mtk_eth *eth, + phy_interface_t interface) +{ + u32 val; + + /* Check DDR memory type. + * Currently TRGMII mode with DDR2 memory is not supported. + */ + regmap_read(eth->ethsys, ETHSYS_SYSCFG, &val); + if (interface == PHY_INTERFACE_MODE_TRGMII && + val & SYSCFG_DRAM_TYPE_DDR2) { + dev_err(eth->dev, + "TRGMII mode with DDR2 memory is not supported!\n"); + return -EOPNOTSUPP; + } + + val = (interface == PHY_INTERFACE_MODE_TRGMII) ? + ETHSYS_TRGMII_MT7621_DDR_PLL : 0; + + regmap_update_bits(eth->ethsys, ETHSYS_CLKCFG0, + ETHSYS_TRGMII_MT7621_MASK, val); + + return 0; +} + static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed) { u32 val; @@ -165,47 +186,6 @@ static void mtk_gmac0_rgmii_adjust(struct mtk_eth *eth, int speed) 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); @@ -228,9 +208,17 @@ static void mtk_phy_link_adjust(struct net_device *dev) break; } - if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && - !mac->id && !mac->trgmii) - mtk_gmac0_rgmii_adjust(mac->hw, dev->phydev->speed); + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GMAC1_TRGMII) && !mac->id) { + if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII_MT7621_CLK)) { + if (mt7621_gmac0_rgmii_adjust(mac->hw, + dev->phydev->interface)) + return; + } else { + if (!mac->trgmii) + mtk_gmac0_rgmii_adjust(mac->hw, + dev->phydev->speed); + } + } if (dev->phydev->link) mcr |= MAC_MCR_FORCE_LINK; @@ -295,6 +283,7 @@ static int mtk_phy_connect(struct net_device *dev) 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); @@ -304,6 +293,10 @@ static int mtk_phy_connect(struct net_device *dev) 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: @@ -312,12 +305,10 @@ static int mtk_phy_connect(struct net_device *dev) case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_ID: 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: @@ -1778,6 +1769,7 @@ static void mtk_poll_controller(struct net_device *dev) static int mtk_start_dma(struct mtk_eth *eth) { + u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; int err; err = mtk_dma_init(eth); @@ -1794,7 +1786,7 @@ static int mtk_start_dma(struct mtk_eth *eth) MTK_QDMA_GLO_CFG); mtk_w32(eth, - MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | + MTK_RX_DMA_EN | rx_2b_offset | MTK_RX_BT_32DWORDS | MTK_MULTI_EN, MTK_PDMA_GLO_CFG); @@ -2298,13 +2290,13 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, switch (cmd->cmd) { case ETHTOOL_GRXRINGS: - if (dev->features & NETIF_F_LRO) { + if (dev->hw_features & NETIF_F_LRO) { cmd->data = MTK_MAX_RX_RING_NUM; ret = 0; } break; case ETHTOOL_GRXCLSRLCNT: - if (dev->features & NETIF_F_LRO) { + if (dev->hw_features & NETIF_F_LRO) { struct mtk_mac *mac = netdev_priv(dev); cmd->rule_cnt = mac->hwlro_ip_cnt; @@ -2312,11 +2304,11 @@ static int mtk_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, } break; case ETHTOOL_GRXCLSRULE: - if (dev->features & NETIF_F_LRO) + if (dev->hw_features & NETIF_F_LRO) ret = mtk_hwlro_get_fdir_entry(dev, cmd); break; case ETHTOOL_GRXCLSRLALL: - if (dev->features & NETIF_F_LRO) + if (dev->hw_features & NETIF_F_LRO) ret = mtk_hwlro_get_fdir_all(dev, cmd, rule_locs); break; @@ -2333,11 +2325,11 @@ static int mtk_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS: - if (dev->features & NETIF_F_LRO) + if (dev->hw_features & NETIF_F_LRO) ret = mtk_hwlro_add_ipaddr(dev, cmd); break; case ETHTOOL_SRXCLSRLDEL: - if (dev->features & NETIF_F_LRO) + if (dev->hw_features & NETIF_F_LRO) ret = mtk_hwlro_del_ipaddr(dev, cmd); break; default: @@ -2482,16 +2474,28 @@ static int mtk_probe(struct platform_device *pdev) 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_err(&pdev->dev, "no infracfg 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"); @@ -2544,8 +2548,10 @@ static int mtk_probe(struct platform_device *pdev) continue; err = mtk_add_mac(eth, mac_np); - if (err) + if (err) { + of_node_put(mac_np); goto err_deinit_hw; + } } if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT)) { @@ -2630,34 +2636,43 @@ static int mtk_remove(struct platform_device *pdev) } 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, }; static const struct mtk_soc_data mt7621_data = { - .caps = MTK_SHARED_INT, + .caps = MT7621_CAPS, .required_clks = MT7621_CLKS_BITMAP, .required_pctl = false, }; 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, }; 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, }; +static const struct mtk_soc_data mt7629_data = { + .ana_rgc3 = 0x128, + .caps = MT7629_CAPS | MTK_HWLRO, + .required_clks = MT7629_CLKS_BITMAP, + .required_pctl = false, +}; + const struct of_device_id of_mtk_match[] = { { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, + { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, {}, }; MODULE_DEVICE_TABLE(of, of_mtk_match); |