diff options
Diffstat (limited to 'drivers/net/ethernet/nxp/lpc_eth.c')
| -rw-r--r-- | drivers/net/ethernet/nxp/lpc_eth.c | 153 |
1 files changed, 67 insertions, 86 deletions
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 89d17399fb5a..8b9a3e3bba30 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/net/ethernet/nxp/lpc_eth.c * @@ -5,16 +6,6 @@ * * Copyright (C) 2010 NXP Semiconductors * Copyright (C) 2012 Roland Stigge <stigge@antcom.de> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -23,14 +14,13 @@ #include <linux/crc32.h> #include <linux/etherdevice.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_mdio.h> #include <linux/of_net.h> #include <linux/phy.h> #include <linux/platform_device.h> #include <linux/spinlock.h> - -#include <mach/board.h> -#include <mach/hardware.h> -#include <mach/platform.h> +#include <linux/soc/nxp/lpc32xx-misc.h> #define MODNAME "lpc-eth" #define DRV_VERSION "1.00" @@ -402,6 +392,7 @@ struct rx_status_t { struct netdata_local { struct platform_device *pdev; struct net_device *ndev; + struct device_node *phy_node; spinlock_t lock; void __iomem *net_base; u32 msg_enable; @@ -428,7 +419,7 @@ struct netdata_local { /* * MAC support functions */ -static void __lpc_set_mac(struct netdata_local *pldat, u8 *mac) +static void __lpc_set_mac(struct netdata_local *pldat, const u8 *mac) { u32 tmp; @@ -760,22 +751,26 @@ static void lpc_handle_link_change(struct net_device *ndev) static int lpc_mii_probe(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = phy_find_first(pldat->mii_bus); - - if (!phydev) { - netdev_err(ndev, "no PHY found\n"); - return -ENODEV; - } + struct phy_device *phydev; /* Attach to the PHY */ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) netdev_info(ndev, "using MII interface\n"); else netdev_info(ndev, "using RMII interface\n"); + + if (pldat->phy_node) + phydev = of_phy_find_device(pldat->phy_node); + else + phydev = phy_find_first(pldat->mii_bus); + if (!phydev) { + netdev_err(ndev, "no PHY found\n"); + return -ENODEV; + } + phydev = phy_connect(ndev, phydev_name(phydev), &lpc_handle_link_change, lpc_phy_interface_mode(&pldat->pdev->dev)); - if (IS_ERR(phydev)) { netdev_err(ndev, "Could not attach to PHY\n"); return PTR_ERR(phydev); @@ -794,6 +789,7 @@ static int lpc_mii_probe(struct net_device *ndev) static int lpc_mii_init(struct netdata_local *pldat) { + struct device_node *node; int err = -ENXIO; pldat->mii_bus = mdiobus_alloc(); @@ -821,12 +817,14 @@ static int lpc_mii_init(struct netdata_local *pldat) pldat->mii_bus->priv = pldat; pldat->mii_bus->parent = &pldat->pdev->dev; - platform_set_drvdata(pldat->pdev, pldat->mii_bus); - - if (mdiobus_register(pldat->mii_bus)) + node = of_get_child_by_name(pldat->pdev->dev.of_node, "mdio"); + err = of_mdiobus_register(pldat->mii_bus, node); + of_node_put(node); + if (err) goto err_out_unregister_bus; - if (lpc_mii_probe(pldat->ndev) != 0) + err = lpc_mii_probe(pldat->ndev); + if (err) goto err_out_unregister_bus; return 0; @@ -1017,9 +1015,6 @@ static int lpc_eth_close(struct net_device *ndev) napi_disable(&pldat->napi); netif_stop_queue(ndev); - if (ndev->phydev) - phy_stop(ndev->phydev); - spin_lock_irqsave(&pldat->lock, flags); __lpc_eth_reset(pldat); netif_carrier_off(ndev); @@ -1027,12 +1022,15 @@ static int lpc_eth_close(struct net_device *ndev) writel(0, LPC_ENET_MAC2(pldat->net_base)); spin_unlock_irqrestore(&pldat->lock, flags); + if (ndev->phydev) + phy_stop(ndev->phydev); clk_disable_unprepare(pldat->clk); return 0; } -static int lpc_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +static netdev_tx_t lpc_eth_hard_start_xmit(struct sk_buff *skb, + struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); u32 len, txidx; @@ -1045,7 +1043,8 @@ static int lpc_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) if (pldat->num_used_tx_buffs >= (ENET_TX_DESC - 1)) { /* This function should never be called when there are no - buffers */ + * buffers + */ netif_stop_queue(ndev); spin_unlock_irq(&pldat->lock); WARN(1, "BUG! TX request when no free TX buffers!\n"); @@ -1093,7 +1092,7 @@ static int lpc_set_mac_address(struct net_device *ndev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN); + eth_hw_addr_set(ndev, addr->sa_data); spin_lock_irqsave(&pldat->lock, flags); @@ -1152,19 +1151,6 @@ static void lpc_eth_set_multicast_list(struct net_device *ndev) spin_unlock_irqrestore(&pldat->lock, flags); } -static int lpc_eth_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) -{ - struct phy_device *phydev = ndev->phydev; - - if (!netif_running(ndev)) - return -EINVAL; - - if (!phydev) - return -ENODEV; - - return phy_mii_ioctl(phydev, req, cmd); -} - static int lpc_eth_open(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); @@ -1198,9 +1184,9 @@ static int lpc_eth_open(struct net_device *ndev) static void lpc_eth_ethtool_getdrvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - strlcpy(info->driver, MODNAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev_name(ndev->dev.parent), + strscpy(info->driver, MODNAME, sizeof(info->driver)); + strscpy(info->version, DRV_VERSION, sizeof(info->version)); + strscpy(info->bus_info, dev_name(ndev->dev.parent), sizeof(info->bus_info)); } @@ -1232,7 +1218,7 @@ static const struct net_device_ops lpc_netdev_ops = { .ndo_stop = lpc_eth_close, .ndo_start_xmit = lpc_eth_hard_start_xmit, .ndo_set_rx_mode = lpc_eth_set_multicast_list, - .ndo_do_ioctl = lpc_eth_ioctl, + .ndo_eth_ioctl = phy_do_ioctl_running, .ndo_set_mac_address = lpc_set_mac_address, .ndo_validate_addr = eth_validate_addr, }; @@ -1245,17 +1231,11 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) struct net_device *ndev; dma_addr_t dma_handle; struct resource *res; + u8 addr[ETH_ALEN]; int irq, ret; - u32 tmp; /* Setup network interface for RMII or MII mode */ - tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL); - tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK; - if (lpc_phy_interface_mode(dev) == PHY_INTERFACE_MODE_MII) - tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS; - else - tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS; - __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL); + lpc32xx_set_phy_interface_mode(lpc_phy_interface_mode(dev)); /* Get platform resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1320,19 +1300,18 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) /* Get size of DMA buffers/descriptors region */ pldat->dma_buff_size = (ENET_TX_DESC + ENET_RX_DESC) * (ENET_MAXF_SIZE + sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t)); - pldat->dma_buff_base_v = 0; if (use_iram_for_net(dev)) { - dma_handle = LPC32XX_IRAM_BASE; - if (pldat->dma_buff_size <= lpc32xx_return_iram_size()) - pldat->dma_buff_base_v = - io_p2v(LPC32XX_IRAM_BASE); - else + if (pldat->dma_buff_size > + lpc32xx_return_iram(&pldat->dma_buff_base_v, &dma_handle)) { + pldat->dma_buff_base_v = NULL; + pldat->dma_buff_size = 0; netdev_err(ndev, "IRAM not big enough for net buffers, using SDRAM instead.\n"); + } } - if (pldat->dma_buff_base_v == 0) { + if (pldat->dma_buff_base_v == NULL) { ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) goto err_out_free_irq; @@ -1340,7 +1319,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) pldat->dma_buff_size = PAGE_ALIGN(pldat->dma_buff_size); /* Allocate a chunk of memory for the DMA ethernet buffers - and descriptors */ + * and descriptors + */ pldat->dma_buff_base_v = dma_alloc_coherent(dev, pldat->dma_buff_size, &dma_handle, @@ -1353,30 +1333,29 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) pldat->dma_buff_base_p = dma_handle; netdev_dbg(ndev, "IO address space :%pR\n", res); - netdev_dbg(ndev, "IO address size :%d\n", resource_size(res)); + netdev_dbg(ndev, "IO address size :%zd\n", + (size_t)resource_size(res)); netdev_dbg(ndev, "IO address (mapped) :0x%p\n", pldat->net_base); netdev_dbg(ndev, "IRQ number :%d\n", ndev->irq); - netdev_dbg(ndev, "DMA buffer size :%d\n", pldat->dma_buff_size); - netdev_dbg(ndev, "DMA buffer P address :0x%08x\n", - pldat->dma_buff_base_p); + netdev_dbg(ndev, "DMA buffer size :%zd\n", pldat->dma_buff_size); + netdev_dbg(ndev, "DMA buffer P address :%pad\n", + &pldat->dma_buff_base_p); netdev_dbg(ndev, "DMA buffer V address :0x%p\n", pldat->dma_buff_base_v); + pldat->phy_node = of_parse_phandle(np, "phy-handle", 0); + /* Get MAC address from current HW setting (POR state is all zeros) */ - __lpc_get_mac(pldat, ndev->dev_addr); + __lpc_get_mac(pldat, addr); + eth_hw_addr_set(ndev, addr); if (!is_valid_ether_addr(ndev->dev_addr)) { - const char *macaddr = of_get_mac_address(np); - if (macaddr) - memcpy(ndev->dev_addr, macaddr, ETH_ALEN); + of_get_ethdev_address(np, ndev); } if (!is_valid_ether_addr(ndev->dev_addr)) eth_hw_addr_random(ndev); - /* Reset the ethernet controller */ - __lpc_eth_reset(pldat); - /* then shut everything down to save power */ __lpc_eth_shutdown(pldat); @@ -1387,13 +1366,14 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) __lpc_mii_mngt_reset(pldat); /* Force default PHY interface setup in chip, this will probably be - changed by the PHY driver */ + * changed by the PHY driver + */ pldat->link = 0; pldat->speed = 100; pldat->duplex = DUPLEX_FULL; __lpc_params_setup(pldat); - netif_napi_add(ndev, &pldat->napi, lpc_eth_poll, NAPI_WEIGHT); + netif_napi_add_weight(ndev, &pldat->napi, lpc_eth_poll, NAPI_WEIGHT); ret = register_netdev(ndev); if (ret) { @@ -1406,8 +1386,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) if (ret) goto err_out_unregister_netdev; - netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", - res->start, ndev->irq); + netdev_info(ndev, "LPC mac at 0x%08lx irq %d\n", + (unsigned long)res->start, ndev->irq); device_init_wakeup(dev, 1); device_set_wakeup_enable(dev, 0); @@ -1418,7 +1398,7 @@ err_out_unregister_netdev: unregister_netdev(ndev); err_out_dma_unmap: if (!use_iram_for_net(dev) || - pldat->dma_buff_size > lpc32xx_return_iram_size()) + pldat->dma_buff_size > lpc32xx_return_iram(NULL, NULL)) dma_free_coherent(dev, pldat->dma_buff_size, pldat->dma_buff_base_v, pldat->dma_buff_base_p); @@ -1437,7 +1417,7 @@ err_exit: return ret; } -static int lpc_eth_drv_remove(struct platform_device *pdev) +static void lpc_eth_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct netdata_local *pldat = netdev_priv(ndev); @@ -1445,7 +1425,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev) unregister_netdev(ndev); if (!use_iram_for_net(&pldat->pdev->dev) || - pldat->dma_buff_size > lpc32xx_return_iram_size()) + pldat->dma_buff_size > lpc32xx_return_iram(NULL, NULL)) dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size, pldat->dma_buff_base_v, pldat->dma_buff_base_p); @@ -1456,8 +1436,6 @@ static int lpc_eth_drv_remove(struct platform_device *pdev) clk_disable_unprepare(pldat->clk); clk_put(pldat->clk); free_netdev(ndev); - - return 0; } #ifdef CONFIG_PM @@ -1491,6 +1469,7 @@ static int lpc_eth_drv_resume(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct netdata_local *pldat; + int ret; if (device_may_wakeup(&pdev->dev)) disable_irq_wake(ndev->irq); @@ -1500,7 +1479,9 @@ static int lpc_eth_drv_resume(struct platform_device *pdev) pldat = netdev_priv(ndev); /* Enable interface clock */ - clk_enable(pldat->clk); + ret = clk_enable(pldat->clk); + if (ret) + return ret; /* Reset and initialize */ __lpc_eth_reset(pldat); |
