summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c356
1 files changed, 194 insertions, 162 deletions
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index a863f7841210..1e91e79c8134 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -33,6 +33,17 @@
#define DRV_NAME "ftgmac100"
+enum ftgmac100_mac_id {
+ FTGMAC100_FARADAY = 1,
+ FTGMAC100_AST2400,
+ FTGMAC100_AST2500,
+ FTGMAC100_AST2600
+};
+
+struct ftgmac100_match_data {
+ enum ftgmac100_mac_id mac_id;
+};
+
/* Arbitrary values, I am not sure the HW has limits */
#define MAX_RX_QUEUE_ENTRIES 1024
#define MAX_TX_QUEUE_ENTRIES 1024
@@ -66,6 +77,8 @@ struct ftgmac100 {
struct resource *res;
void __iomem *base;
+ enum ftgmac100_mac_id mac_id;
+
/* Rx ring */
unsigned int rx_q_entries;
struct ftgmac100_rxdes *rxdes;
@@ -1470,6 +1483,11 @@ static int ftgmac100_mii_probe(struct net_device *netdev)
phy_interface_t phy_intf;
int err;
+ if (!priv->mii_bus) {
+ dev_err(priv->dev, "No MDIO bus available\n");
+ return -ENODEV;
+ }
+
/* Default to RGMII. It's a gigabit part after all */
err = of_get_phy_mode(np, &phy_intf);
if (err)
@@ -1699,16 +1717,16 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
struct platform_device *pdev = to_platform_device(priv->dev);
struct device_node *np = pdev->dev.of_node;
struct device_node *mdio_np;
- int i, err = 0;
+ int err = 0;
u32 reg;
/* initialize mdio bus */
- priv->mii_bus = mdiobus_alloc();
+ priv->mii_bus = devm_mdiobus_alloc(priv->dev);
if (!priv->mii_bus)
return -EIO;
- if (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac")) {
+ if (priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500) {
/* The AST2600 has a separate MDIO controller */
/* For the AST2400 and AST2500 this driver only supports the
@@ -1727,24 +1745,16 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
priv->mii_bus->read = ftgmac100_mdiobus_read;
priv->mii_bus->write = ftgmac100_mdiobus_write;
- for (i = 0; i < PHY_MAX_ADDR; i++)
- priv->mii_bus->irq[i] = PHY_POLL;
-
mdio_np = of_get_child_by_name(np, "mdio");
- err = of_mdiobus_register(priv->mii_bus, mdio_np);
+ err = devm_of_mdiobus_register(priv->dev, priv->mii_bus, mdio_np);
+ of_node_put(mdio_np);
if (err) {
dev_err(priv->dev, "Cannot register MDIO bus!\n");
- goto err_register_mdiobus;
+ return err;
}
- of_node_put(mdio_np);
-
return 0;
-
-err_register_mdiobus:
- mdiobus_free(priv->mii_bus);
- return err;
}
static void ftgmac100_phy_disconnect(struct net_device *netdev)
@@ -1763,17 +1773,6 @@ static void ftgmac100_phy_disconnect(struct net_device *netdev)
fixed_phy_unregister(phydev);
}
-static void ftgmac100_destroy_mdio(struct net_device *netdev)
-{
- struct ftgmac100 *priv = netdev_priv(netdev);
-
- if (!priv->mii_bus)
- return;
-
- mdiobus_unregister(priv->mii_bus);
- mdiobus_free(priv->mii_bus);
-}
-
static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
{
if (unlikely(nd->state != ncsi_dev_state_functional))
@@ -1788,13 +1787,10 @@ static int ftgmac100_setup_clk(struct ftgmac100 *priv)
struct clk *clk;
int rc;
- clk = devm_clk_get(priv->dev, NULL /* MACCLK */);
+ clk = devm_clk_get_enabled(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
@@ -1803,21 +1799,17 @@ static int ftgmac100_setup_clk(struct ftgmac100 *priv)
rc = clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ :
FTGMAC_100MHZ);
if (rc)
- goto cleanup_clk;
+ return rc;
/* RCLK is for RMII, typically used for NCSI. Optional because it's 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);
+ priv->rclk = devm_clk_get_optional_enabled(priv->dev, "RCLK");
+ if (IS_ERR(priv->rclk))
+ return PTR_ERR(priv->rclk);
- return rc;
+ return 0;
}
static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
@@ -1833,16 +1825,121 @@ static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
return ret;
}
+static int ftgmac100_probe_ncsi(struct net_device *netdev,
+ struct ftgmac100 *priv,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct phy_device *phydev;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ dev_err(&pdev->dev, "NCSI stack not enabled\n");
+ return -EINVAL;
+ }
+
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ priv->use_ncsi = true;
+ priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
+ if (!priv->ndev)
+ return -EINVAL;
+
+ phydev = fixed_phy_register(&ncsi_phy_status, np);
+ if (IS_ERR(phydev)) {
+ dev_err(&pdev->dev, "failed to register fixed PHY device\n");
+ err = PTR_ERR(phydev);
+ goto err_register_ndev;
+ }
+ err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link,
+ PHY_INTERFACE_MODE_RMII);
+ if (err) {
+ dev_err(&pdev->dev, "Connecting PHY failed\n");
+ goto err_register_phy;
+ }
+
+ return 0;
+err_register_phy:
+ fixed_phy_unregister(phydev);
+err_register_ndev:
+ if (priv->ndev)
+ ncsi_unregister_dev(priv->ndev);
+ priv->ndev = NULL;
+ return err;
+}
+
+static int ftgmac100_probe_dt(struct net_device *netdev,
+ struct platform_device *pdev,
+ struct ftgmac100 *priv,
+ struct device_node *np)
+{
+ struct phy_device *phy;
+ int err;
+
+ if (of_get_property(np, "use-ncsi", NULL))
+ return ftgmac100_probe_ncsi(netdev, priv, pdev);
+
+ if (of_phy_is_fixed_link(np) ||
+ of_get_property(np, "phy-handle", NULL)) {
+ /* Support "mdio"/"phy" child nodes for ast2400/2500
+ * with an embedded MDIO controller. Automatically
+ * scan the DTS for available PHYs and register
+ * them. 2600 has an independent MDIO controller, not
+ * part of the MAC.
+ */
+ phy = of_phy_get_and_connect(priv->netdev, np,
+ &ftgmac100_adjust_link);
+ if (!phy) {
+ dev_err(&pdev->dev, "Failed to connect to phy\n");
+ return -EINVAL;
+ }
+
+ /* 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);
+ return 0;
+ }
+
+ if (!ftgmac100_has_child_node(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.
+ */
+ err = ftgmac100_mii_probe(netdev);
+ if (err) {
+ dev_err(priv->dev, "MII probe failed!\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int ftgmac100_probe(struct platform_device *pdev)
{
+ const struct ftgmac100_match_data *match_data;
+ enum ftgmac100_mac_id mac_id;
struct resource *res;
int irq;
struct net_device *netdev;
- struct phy_device *phydev;
struct ftgmac100 *priv;
struct device_node *np;
int err = 0;
+ np = pdev->dev.of_node;
+ if (np) {
+ match_data = of_device_get_match_data(&pdev->dev);
+ if (!match_data)
+ return -EINVAL;
+ mac_id = match_data->mac_id;
+ } else {
+ mac_id = FTGMAC100_FARADAY;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
@@ -1852,11 +1949,9 @@ static int ftgmac100_probe(struct platform_device *pdev)
return irq;
/* setup net_device */
- netdev = alloc_etherdev(sizeof(*priv));
- if (!netdev) {
- err = -ENOMEM;
- goto err_alloc_etherdev;
- }
+ netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv));
+ if (!netdev)
+ return -ENOMEM;
SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1870,22 +1965,22 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->dev = &pdev->dev;
+ priv->mac_id = mac_id;
INIT_WORK(&priv->reset_task, ftgmac100_reset_task);
/* map io memory */
- priv->res = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
+ priv->res = devm_request_mem_region(&pdev->dev,
+ res->start, resource_size(res),
+ dev_name(&pdev->dev));
if (!priv->res) {
dev_err(&pdev->dev, "Could not reserve memory region\n");
- err = -ENOMEM;
- goto err_req_mem;
+ return -ENOMEM;
}
- priv->base = ioremap(res->start, resource_size(res));
+ priv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!priv->base) {
dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
- err = -EIO;
- goto err_ioremap;
+ return -EIO;
}
netdev->irq = irq;
@@ -1898,12 +1993,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
/* MAC address from chip or random one */
err = ftgmac100_initial_mac(priv);
if (err)
- goto err_phy_connect;
+ return err;
- 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,ast2600-mac"))) {
+ if (priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500 ||
+ priv->mac_id == FTGMAC100_AST2600) {
priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30);
priv->is_aspeed = true;
@@ -1912,100 +2006,37 @@ static int ftgmac100_probe(struct platform_device *pdev)
priv->txdes0_edotr_mask = BIT(15);
}
- if (np && of_get_property(np, "use-ncsi", NULL)) {
- if (!IS_ENABLED(CONFIG_NET_NCSI)) {
- dev_err(&pdev->dev, "NCSI stack not enabled\n");
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- dev_info(&pdev->dev, "Using NCSI interface\n");
- priv->use_ncsi = true;
- priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
- if (!priv->ndev) {
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- phydev = fixed_phy_register(&ncsi_phy_status, np);
- if (IS_ERR(phydev)) {
- dev_err(&pdev->dev, "failed to register fixed PHY device\n");
- err = PTR_ERR(phydev);
- goto err_phy_connect;
- }
- err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link,
- PHY_INTERFACE_MODE_RMII);
- if (err) {
- dev_err(&pdev->dev, "Connecting PHY failed\n");
- goto err_phy_connect;
- }
- } else if (np && (of_phy_is_fixed_link(np) ||
- of_get_property(np, "phy-handle", NULL))) {
- struct phy_device *phy;
-
- /* Support "mdio"/"phy" child nodes for ast2400/2500 with
- * an embedded MDIO controller. Automatically scan the DTS for
- * available PHYs and register them.
- */
- if (of_get_property(np, "phy-handle", NULL) &&
- (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
- of_device_is_compatible(np, "aspeed,ast2500-mac"))) {
- err = ftgmac100_setup_mdio(netdev);
- if (err)
- goto err_setup_mdio;
- }
-
- phy = of_phy_get_and_connect(priv->netdev, np,
- &ftgmac100_adjust_link);
- if (!phy) {
- dev_err(&pdev->dev, "Failed to connect to phy\n");
- err = -EINVAL;
- goto err_phy_connect;
- }
-
- /* 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 && !ftgmac100_has_child_node(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;
+ if (priv->mac_id == FTGMAC100_FARADAY ||
+ priv->mac_id == FTGMAC100_AST2400 ||
+ priv->mac_id == FTGMAC100_AST2500) {
err = ftgmac100_setup_mdio(netdev);
if (err)
- goto err_setup_mdio;
-
- err = ftgmac100_mii_probe(netdev);
- if (err) {
- dev_err(priv->dev, "MII probe failed!\n");
- goto err_ncsi_dev;
- }
+ return err;
+ }
+ if (np) {
+ err = ftgmac100_probe_dt(netdev, pdev, priv, np);
+ if (err)
+ goto err;
}
priv->rst = devm_reset_control_get_optional_exclusive(priv->dev, NULL);
if (IS_ERR(priv->rst)) {
err = PTR_ERR(priv->rst);
- goto err_phy_connect;
+ goto err;
}
if (priv->is_aspeed) {
err = ftgmac100_setup_clk(priv);
if (err)
- goto err_phy_connect;
-
- /* Disable ast2600 problematic HW arbitration */
- if (of_device_is_compatible(np, "aspeed,ast2600-mac"))
- iowrite32(FTGMAC100_TM_DEFAULT,
- priv->base + FTGMAC100_OFFSET_TM);
+ goto err;
}
+ /* Disable ast2600 problematic HW arbitration */
+ if (priv->mac_id == FTGMAC100_AST2600)
+ iowrite32(FTGMAC100_TM_DEFAULT,
+ priv->base + FTGMAC100_OFFSET_TM);
+
/* Default ring sizes */
priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
priv->tx_q_entries = priv->new_tx_q_entries = DEF_TX_QUEUE_ENTRIES;
@@ -2019,11 +2050,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
/* AST2400 doesn't have working HW checksum generation */
- if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
+ if (priv->mac_id == FTGMAC100_AST2400)
netdev->hw_features &= ~NETIF_F_HW_CSUM;
/* AST2600 tx checksum with NCSI is broken */
- if (priv->use_ncsi && of_device_is_compatible(np, "aspeed,ast2600-mac"))
+ if (priv->use_ncsi && priv->mac_id == FTGMAC100_AST2600)
netdev->hw_features &= ~NETIF_F_HW_CSUM;
if (np && of_get_property(np, "no-hw-checksum", NULL))
@@ -2034,29 +2065,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
err = register_netdev(netdev);
if (err) {
dev_err(&pdev->dev, "Failed to register netdev\n");
- goto err_register_netdev;
+ goto err;
}
netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
return 0;
-err_register_netdev:
- clk_disable_unprepare(priv->rclk);
- clk_disable_unprepare(priv->clk);
-err_phy_connect:
+err:
ftgmac100_phy_disconnect(netdev);
-err_ncsi_dev:
if (priv->ndev)
ncsi_unregister_dev(priv->ndev);
- ftgmac100_destroy_mdio(netdev);
-err_setup_mdio:
- iounmap(priv->base);
-err_ioremap:
- release_resource(priv->res);
-err_req_mem:
- free_netdev(netdev);
-err_alloc_etherdev:
return err;
}
@@ -2072,26 +2091,39 @@ static void ftgmac100_remove(struct platform_device *pdev)
ncsi_unregister_dev(priv->ndev);
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,
* during stop, make sure it's gone before we free the structure.
*/
cancel_work_sync(&priv->reset_task);
ftgmac100_phy_disconnect(netdev);
- ftgmac100_destroy_mdio(netdev);
+}
- iounmap(priv->base);
- release_resource(priv->res);
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2400 = {
+ .mac_id = FTGMAC100_AST2400
+};
- netif_napi_del(&priv->napi);
- free_netdev(netdev);
-}
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2500 = {
+ .mac_id = FTGMAC100_AST2500
+};
+
+static const struct ftgmac100_match_data ftgmac100_match_data_ast2600 = {
+ .mac_id = FTGMAC100_AST2600
+};
+
+static const struct ftgmac100_match_data ftgmac100_match_data_faraday = {
+ .mac_id = FTGMAC100_FARADAY
+};
static const struct of_device_id ftgmac100_of_match[] = {
- { .compatible = "faraday,ftgmac100" },
+ { .compatible = "aspeed,ast2400-mac",
+ .data = &ftgmac100_match_data_ast2400},
+ { .compatible = "aspeed,ast2500-mac",
+ .data = &ftgmac100_match_data_ast2500 },
+ { .compatible = "aspeed,ast2600-mac",
+ .data = &ftgmac100_match_data_ast2600 },
+ { .compatible = "faraday,ftgmac100",
+ .data = &ftgmac100_match_data_faraday },
{ }
};
MODULE_DEVICE_TABLE(of, ftgmac100_of_match);