diff options
Diffstat (limited to 'drivers/net/ethernet/faraday/ftgmac100.c')
-rw-r--r-- | drivers/net/ethernet/faraday/ftgmac100.c | 133 |
1 files changed, 91 insertions, 42 deletions
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 030fed65393e..4572797f00d7 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/of.h> +#include <linux/of_mdio.h> #include <linux/phy.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -89,6 +90,9 @@ struct ftgmac100 { struct mii_bus *mii_bus; struct clk *clk; + /* AST2500/AST2600 RMII ref clock gate */ + struct clk *rclk; + /* Link management */ int cur_speed; int cur_duplex; @@ -726,6 +730,18 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, */ nfrags = skb_shinfo(skb)->nr_frags; + /* Setup HW checksumming */ + csum_vlan = 0; + if (skb->ip_summed == CHECKSUM_PARTIAL && + !ftgmac100_prep_tx_csum(skb, &csum_vlan)) + goto drop; + + /* Add VLAN tag */ + if (skb_vlan_tag_present(skb)) { + csum_vlan |= FTGMAC100_TXDES1_INS_VLANTAG; + csum_vlan |= skb_vlan_tag_get(skb) & 0xffff; + } + /* Get header len */ len = skb_headlen(skb); @@ -752,19 +768,6 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, if (nfrags == 0) f_ctl_stat |= FTGMAC100_TXDES0_LTS; txdes->txdes3 = cpu_to_le32(map); - - /* Setup HW checksumming */ - csum_vlan = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL && - !ftgmac100_prep_tx_csum(skb, &csum_vlan)) - goto drop; - - /* Add VLAN tag */ - if (skb_vlan_tag_present(skb)) { - csum_vlan |= FTGMAC100_TXDES1_INS_VLANTAG; - csum_vlan |= skb_vlan_tag_get(skb) & 0xffff; - } - txdes->txdes1 = cpu_to_le32(csum_vlan); /* Next descriptor */ @@ -774,7 +777,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, for (i = 0; i < nfrags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - len = frag->size; + len = skb_frag_size(frag); /* Map it */ map = skb_frag_dma_map(priv->dev, frag, 0, len, @@ -1533,16 +1536,7 @@ static int ftgmac100_stop(struct net_device *netdev) return 0; } -/* optional */ -static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - if (!netdev->phydev) - return -ENXIO; - - return phy_mii_ioctl(netdev->phydev, ifr, cmd); -} - -static void ftgmac100_tx_timeout(struct net_device *netdev) +static void ftgmac100_tx_timeout(struct net_device *netdev, unsigned int txqueue) { struct ftgmac100 *priv = netdev_priv(netdev); @@ -1594,7 +1588,7 @@ static const struct net_device_ops ftgmac100_netdev_ops = { .ndo_start_xmit = ftgmac100_hard_start_xmit, .ndo_set_mac_address = ftgmac100_set_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = ftgmac100_do_ioctl, + .ndo_do_ioctl = phy_do_ioctl, .ndo_tx_timeout = ftgmac100_tx_timeout, .ndo_set_rx_mode = ftgmac100_set_rx_mode, .ndo_set_features = ftgmac100_set_features, @@ -1609,7 +1603,7 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); struct platform_device *pdev = to_platform_device(priv->dev); - int phy_intf = PHY_INTERFACE_MODE_RGMII; + phy_interface_t phy_intf = PHY_INTERFACE_MODE_RGMII; struct device_node *np = pdev->dev.of_node; int i, err = 0; u32 reg; @@ -1619,8 +1613,13 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) if (!priv->mii_bus) return -EIO; - if (priv->is_aspeed) { - /* This driver supports the old MDIO interface */ + if (of_device_is_compatible(np, "aspeed,ast2400-mac") || + of_device_is_compatible(np, "aspeed,ast2500-mac")) { + /* The AST2600 has a separate MDIO controller */ + + /* For the AST2400 and AST2500 this driver only supports the + * old MDIO interface + */ reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR); reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE; iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR); @@ -1629,8 +1628,8 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) /* Get PHY mode from device-tree */ if (np) { /* Default to RGMII. It's a gigabit part after all */ - phy_intf = of_get_phy_mode(np); - if (phy_intf < 0) + err = of_get_phy_mode(np, &phy_intf); + if (err) phy_intf = PHY_INTERFACE_MODE_RGMII; /* Aspeed only supports these. I don't know about other IP @@ -1712,20 +1711,41 @@ static void ftgmac100_ncsi_handler(struct ncsi_dev *nd) nd->link_up ? "up" : "down"); } -static void ftgmac100_setup_clk(struct ftgmac100 *priv) +static int ftgmac100_setup_clk(struct ftgmac100 *priv) { - priv->clk = devm_clk_get(priv->dev, NULL); - if (IS_ERR(priv->clk)) - return; + struct clk *clk; + int rc; - clk_prepare_enable(priv->clk); + clk = devm_clk_get(priv->dev, NULL /* MACCLK */); + if (IS_ERR(clk)) + return PTR_ERR(clk); + priv->clk = clk; + rc = clk_prepare_enable(priv->clk); + if (rc) + return rc; /* Aspeed specifies a 100MHz clock is required for up to * 1000Mbit link speeds. As NCSI is limited to 100Mbit, 25MHz * is sufficient */ - clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ : - FTGMAC_100MHZ); + rc = clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ : + FTGMAC_100MHZ); + if (rc) + goto cleanup_clk; + + /* RCLK is for RMII, typically used for NCSI. Optional because its not + * necessary if it's the AST2400 MAC, or the MAC is configured for + * RGMII, or the controller is not an ASPEED-based controller. + */ + priv->rclk = devm_clk_get_optional(priv->dev, "RCLK"); + rc = clk_prepare_enable(priv->rclk); + if (!rc) + return 0; + +cleanup_clk: + clk_disable_unprepare(priv->clk); + + return rc; } static int ftgmac100_probe(struct platform_device *pdev) @@ -1797,7 +1817,8 @@ static int ftgmac100_probe(struct platform_device *pdev) np = pdev->dev.of_node; if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") || - of_device_is_compatible(np, "aspeed,ast2500-mac"))) { + of_device_is_compatible(np, "aspeed,ast2500-mac") || + of_device_is_compatible(np, "aspeed,ast2600-mac"))) { priv->rxdes0_edorr_mask = BIT(30); priv->txdes0_edotr_mask = BIT(30); priv->is_aspeed = true; @@ -1817,15 +1838,40 @@ static int ftgmac100_probe(struct platform_device *pdev) priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler); if (!priv->ndev) goto err_ncsi_dev; - } else { + } else if (np && of_get_property(np, "phy-handle", NULL)) { + struct phy_device *phy; + + phy = of_phy_get_and_connect(priv->netdev, np, + &ftgmac100_adjust_link); + if (!phy) { + dev_err(&pdev->dev, "Failed to connect to phy\n"); + goto err_setup_mdio; + } + + /* Indicate that we support PAUSE frames (see comment in + * Documentation/networking/phy.rst) + */ + phy_support_asym_pause(phy); + + /* Display what we found */ + phy_attached_info(phy); + } else if (np && !of_get_child_by_name(np, "mdio")) { + /* Support legacy ASPEED devicetree descriptions that decribe a + * MAC with an embedded MDIO controller but have no "mdio" + * child node. Automatically scan the MDIO bus for available + * PHYs. + */ priv->use_ncsi = false; err = ftgmac100_setup_mdio(netdev); if (err) goto err_setup_mdio; } - if (priv->is_aspeed) - ftgmac100_setup_clk(priv); + if (priv->is_aspeed) { + err = ftgmac100_setup_clk(priv); + if (err) + goto err_ncsi_dev; + } /* Default ring sizes */ priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES; @@ -1857,8 +1903,10 @@ static int ftgmac100_probe(struct platform_device *pdev) return 0; -err_ncsi_dev: err_register_netdev: + clk_disable_unprepare(priv->rclk); + clk_disable_unprepare(priv->clk); +err_ncsi_dev: ftgmac100_destroy_mdio(netdev); err_setup_mdio: iounmap(priv->base); @@ -1880,6 +1928,7 @@ static int ftgmac100_remove(struct platform_device *pdev) unregister_netdev(netdev); + clk_disable_unprepare(priv->rclk); clk_disable_unprepare(priv->clk); /* There's a small chance the reset task will have been re-queued, |