1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21edb9ca6SSiva Reddy /* 10G controller driver for Samsung SoCs
31edb9ca6SSiva Reddy *
41edb9ca6SSiva Reddy * Copyright (C) 2013 Samsung Electronics Co., Ltd.
51edb9ca6SSiva Reddy * http://www.samsung.com
61edb9ca6SSiva Reddy *
71edb9ca6SSiva Reddy * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
81edb9ca6SSiva Reddy */
91edb9ca6SSiva Reddy
101edb9ca6SSiva Reddy #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
111edb9ca6SSiva Reddy
121edb9ca6SSiva Reddy #include <linux/etherdevice.h>
131edb9ca6SSiva Reddy #include <linux/io.h>
141edb9ca6SSiva Reddy #include <linux/module.h>
151edb9ca6SSiva Reddy #include <linux/netdevice.h>
161edb9ca6SSiva Reddy #include <linux/of.h>
171edb9ca6SSiva Reddy #include <linux/of_irq.h>
181edb9ca6SSiva Reddy #include <linux/of_net.h>
191edb9ca6SSiva Reddy #include <linux/phy.h>
201edb9ca6SSiva Reddy #include <linux/platform_device.h>
211edb9ca6SSiva Reddy #include <linux/sxgbe_platform.h>
221edb9ca6SSiva Reddy
231edb9ca6SSiva Reddy #include "sxgbe_common.h"
241edb9ca6SSiva Reddy #include "sxgbe_reg.h"
251edb9ca6SSiva Reddy
261edb9ca6SSiva Reddy #ifdef CONFIG_OF
sxgbe_probe_config_dt(struct platform_device * pdev,struct sxgbe_plat_data * plat)271edb9ca6SSiva Reddy static int sxgbe_probe_config_dt(struct platform_device *pdev,
2883216e39SMichael Walle struct sxgbe_plat_data *plat)
291edb9ca6SSiva Reddy {
301edb9ca6SSiva Reddy struct device_node *np = pdev->dev.of_node;
311edb9ca6SSiva Reddy struct sxgbe_dma_cfg *dma_cfg;
320c65b2b9SAndrew Lunn int err;
331edb9ca6SSiva Reddy
341edb9ca6SSiva Reddy if (!np)
351edb9ca6SSiva Reddy return -ENODEV;
361edb9ca6SSiva Reddy
370c65b2b9SAndrew Lunn err = of_get_phy_mode(np, &plat->interface);
380c65b2b9SAndrew Lunn if (err && err != -ENODEV)
390c65b2b9SAndrew Lunn return err;
401edb9ca6SSiva Reddy
411edb9ca6SSiva Reddy plat->bus_id = of_alias_get_id(np, "ethernet");
421edb9ca6SSiva Reddy if (plat->bus_id < 0)
431edb9ca6SSiva Reddy plat->bus_id = 0;
441edb9ca6SSiva Reddy
451edb9ca6SSiva Reddy plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
461edb9ca6SSiva Reddy sizeof(*plat->mdio_bus_data),
471edb9ca6SSiva Reddy GFP_KERNEL);
482207d182SChristophe Jaillet if (!plat->mdio_bus_data)
492207d182SChristophe Jaillet return -ENOMEM;
501edb9ca6SSiva Reddy
511edb9ca6SSiva Reddy dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
521edb9ca6SSiva Reddy if (!dma_cfg)
531edb9ca6SSiva Reddy return -ENOMEM;
541edb9ca6SSiva Reddy
551edb9ca6SSiva Reddy plat->dma_cfg = dma_cfg;
561edb9ca6SSiva Reddy of_property_read_u32(np, "samsung,pbl", &dma_cfg->pbl);
571edb9ca6SSiva Reddy if (of_property_read_u32(np, "samsung,burst-map", &dma_cfg->burst_map) == 0)
581edb9ca6SSiva Reddy dma_cfg->fixed_burst = true;
591edb9ca6SSiva Reddy
601edb9ca6SSiva Reddy return 0;
611edb9ca6SSiva Reddy }
621edb9ca6SSiva Reddy #else
sxgbe_probe_config_dt(struct platform_device * pdev,struct sxgbe_plat_data * plat)631edb9ca6SSiva Reddy static int sxgbe_probe_config_dt(struct platform_device *pdev,
6483216e39SMichael Walle struct sxgbe_plat_data *plat)
651edb9ca6SSiva Reddy {
661edb9ca6SSiva Reddy return -ENOSYS;
671edb9ca6SSiva Reddy }
681edb9ca6SSiva Reddy #endif /* CONFIG_OF */
691edb9ca6SSiva Reddy
701edb9ca6SSiva Reddy /**
711edb9ca6SSiva Reddy * sxgbe_platform_probe
721edb9ca6SSiva Reddy * @pdev: platform device pointer
731edb9ca6SSiva Reddy * Description: platform_device probe function. It allocates
741edb9ca6SSiva Reddy * the necessary resources and invokes the main to init
751edb9ca6SSiva Reddy * the net device, register the mdio bus etc.
761edb9ca6SSiva Reddy */
sxgbe_platform_probe(struct platform_device * pdev)771edb9ca6SSiva Reddy static int sxgbe_platform_probe(struct platform_device *pdev)
781edb9ca6SSiva Reddy {
791edb9ca6SSiva Reddy int ret;
801edb9ca6SSiva Reddy int i, chan;
811edb9ca6SSiva Reddy struct device *dev = &pdev->dev;
821edb9ca6SSiva Reddy void __iomem *addr;
831edb9ca6SSiva Reddy struct sxgbe_priv_data *priv = NULL;
841edb9ca6SSiva Reddy struct sxgbe_plat_data *plat_dat = NULL;
851edb9ca6SSiva Reddy struct net_device *ndev = platform_get_drvdata(pdev);
861edb9ca6SSiva Reddy struct device_node *node = dev->of_node;
871edb9ca6SSiva Reddy
881edb9ca6SSiva Reddy /* Get memory resource */
89ffb36a10SYueHaibing addr = devm_platform_ioremap_resource(pdev, 0);
901edb9ca6SSiva Reddy if (IS_ERR(addr))
911edb9ca6SSiva Reddy return PTR_ERR(addr);
921edb9ca6SSiva Reddy
931edb9ca6SSiva Reddy if (pdev->dev.of_node) {
941edb9ca6SSiva Reddy plat_dat = devm_kzalloc(&pdev->dev,
951edb9ca6SSiva Reddy sizeof(struct sxgbe_plat_data),
961edb9ca6SSiva Reddy GFP_KERNEL);
971edb9ca6SSiva Reddy if (!plat_dat)
981edb9ca6SSiva Reddy return -ENOMEM;
991edb9ca6SSiva Reddy
10083216e39SMichael Walle ret = sxgbe_probe_config_dt(pdev, plat_dat);
1011edb9ca6SSiva Reddy if (ret) {
1021edb9ca6SSiva Reddy pr_err("%s: main dt probe failed\n", __func__);
1031edb9ca6SSiva Reddy return ret;
1041edb9ca6SSiva Reddy }
1051edb9ca6SSiva Reddy }
1061edb9ca6SSiva Reddy
1071edb9ca6SSiva Reddy priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr);
1081edb9ca6SSiva Reddy if (!priv) {
1091edb9ca6SSiva Reddy pr_err("%s: main driver probe failed\n", __func__);
1101edb9ca6SSiva Reddy goto err_out;
1111edb9ca6SSiva Reddy }
1121edb9ca6SSiva Reddy
1131edb9ca6SSiva Reddy /* Get the SXGBE common INT information */
1141edb9ca6SSiva Reddy priv->irq = irq_of_parse_and_map(node, 0);
1151edb9ca6SSiva Reddy if (priv->irq <= 0) {
1161edb9ca6SSiva Reddy dev_err(dev, "sxgbe common irq parsing failed\n");
1171edb9ca6SSiva Reddy goto err_drv_remove;
1181edb9ca6SSiva Reddy }
1191edb9ca6SSiva Reddy
1201c1832c7SGirish K.S /* Get MAC address if available (DT) */
1219ca01b25SJakub Kicinski of_get_ethdev_address(node, priv->dev);
1221c1832c7SGirish K.S
1231edb9ca6SSiva Reddy /* Get the TX/RX IRQ numbers */
1241edb9ca6SSiva Reddy for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {
1251edb9ca6SSiva Reddy priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++);
1261edb9ca6SSiva Reddy if (priv->txq[i]->irq_no <= 0) {
1271edb9ca6SSiva Reddy dev_err(dev, "sxgbe tx irq parsing failed\n");
1281edb9ca6SSiva Reddy goto err_tx_irq_unmap;
1291edb9ca6SSiva Reddy }
1301edb9ca6SSiva Reddy }
1311edb9ca6SSiva Reddy
1321edb9ca6SSiva Reddy for (i = 0; i < SXGBE_RX_QUEUES; i++) {
1331edb9ca6SSiva Reddy priv->rxq[i]->irq_no = irq_of_parse_and_map(node, chan++);
1341edb9ca6SSiva Reddy if (priv->rxq[i]->irq_no <= 0) {
1351edb9ca6SSiva Reddy dev_err(dev, "sxgbe rx irq parsing failed\n");
1361edb9ca6SSiva Reddy goto err_rx_irq_unmap;
1371edb9ca6SSiva Reddy }
1381edb9ca6SSiva Reddy }
1391edb9ca6SSiva Reddy
140acc18c14SGirish K S priv->lpi_irq = irq_of_parse_and_map(node, chan);
141acc18c14SGirish K S if (priv->lpi_irq <= 0) {
142acc18c14SGirish K S dev_err(dev, "sxgbe lpi irq parsing failed\n");
143acc18c14SGirish K S goto err_rx_irq_unmap;
144acc18c14SGirish K S }
145acc18c14SGirish K S
1461edb9ca6SSiva Reddy platform_set_drvdata(pdev, priv->dev);
1471edb9ca6SSiva Reddy
1481edb9ca6SSiva Reddy pr_debug("platform driver registration completed\n");
1491edb9ca6SSiva Reddy
1501edb9ca6SSiva Reddy return 0;
1511edb9ca6SSiva Reddy
1521edb9ca6SSiva Reddy err_rx_irq_unmap:
15379c13423SRasmus Villemoes while (i--)
1541edb9ca6SSiva Reddy irq_dispose_mapping(priv->rxq[i]->irq_no);
1551edb9ca6SSiva Reddy i = SXGBE_TX_QUEUES;
1561edb9ca6SSiva Reddy err_tx_irq_unmap:
15779c13423SRasmus Villemoes while (i--)
1581edb9ca6SSiva Reddy irq_dispose_mapping(priv->txq[i]->irq_no);
1591edb9ca6SSiva Reddy irq_dispose_mapping(priv->irq);
1601edb9ca6SSiva Reddy err_drv_remove:
1611edb9ca6SSiva Reddy sxgbe_drv_remove(ndev);
1621edb9ca6SSiva Reddy err_out:
1631edb9ca6SSiva Reddy return -ENODEV;
1641edb9ca6SSiva Reddy }
1651edb9ca6SSiva Reddy
1661edb9ca6SSiva Reddy /**
1671edb9ca6SSiva Reddy * sxgbe_platform_remove
1681edb9ca6SSiva Reddy * @pdev: platform device pointer
1691edb9ca6SSiva Reddy * Description: this function calls the main to free the net resources
1701edb9ca6SSiva Reddy * and calls the platforms hook and release the resources (e.g. mem).
1711edb9ca6SSiva Reddy */
sxgbe_platform_remove(struct platform_device * pdev)1721edb9ca6SSiva Reddy static int sxgbe_platform_remove(struct platform_device *pdev)
1731edb9ca6SSiva Reddy {
1741edb9ca6SSiva Reddy struct net_device *ndev = platform_get_drvdata(pdev);
1751edb9ca6SSiva Reddy
1761edb9ca6SSiva Reddy sxgbe_drv_remove(ndev);
1771edb9ca6SSiva Reddy
1781edb9ca6SSiva Reddy return 0;
1791edb9ca6SSiva Reddy }
1801edb9ca6SSiva Reddy
1811edb9ca6SSiva Reddy #ifdef CONFIG_PM
sxgbe_platform_suspend(struct device * dev)1821edb9ca6SSiva Reddy static int sxgbe_platform_suspend(struct device *dev)
1831edb9ca6SSiva Reddy {
1841edb9ca6SSiva Reddy struct net_device *ndev = dev_get_drvdata(dev);
1851edb9ca6SSiva Reddy
1861edb9ca6SSiva Reddy return sxgbe_suspend(ndev);
1871edb9ca6SSiva Reddy }
1881edb9ca6SSiva Reddy
sxgbe_platform_resume(struct device * dev)1891edb9ca6SSiva Reddy static int sxgbe_platform_resume(struct device *dev)
1901edb9ca6SSiva Reddy {
1911edb9ca6SSiva Reddy struct net_device *ndev = dev_get_drvdata(dev);
1921edb9ca6SSiva Reddy
1931edb9ca6SSiva Reddy return sxgbe_resume(ndev);
1941edb9ca6SSiva Reddy }
19540b92cadSByungho An
sxgbe_platform_freeze(struct device * dev)1961edb9ca6SSiva Reddy static int sxgbe_platform_freeze(struct device *dev)
1971edb9ca6SSiva Reddy {
1981edb9ca6SSiva Reddy struct net_device *ndev = dev_get_drvdata(dev);
1991edb9ca6SSiva Reddy
2001edb9ca6SSiva Reddy return sxgbe_freeze(ndev);
2011edb9ca6SSiva Reddy }
20240b92cadSByungho An
sxgbe_platform_restore(struct device * dev)2031edb9ca6SSiva Reddy static int sxgbe_platform_restore(struct device *dev)
2041edb9ca6SSiva Reddy {
2051edb9ca6SSiva Reddy struct net_device *ndev = dev_get_drvdata(dev);
2061edb9ca6SSiva Reddy
2071edb9ca6SSiva Reddy return sxgbe_restore(ndev);
2081edb9ca6SSiva Reddy }
2091edb9ca6SSiva Reddy
2101edb9ca6SSiva Reddy static const struct dev_pm_ops sxgbe_platform_pm_ops = {
2111edb9ca6SSiva Reddy .suspend = sxgbe_platform_suspend,
2121edb9ca6SSiva Reddy .resume = sxgbe_platform_resume,
2131edb9ca6SSiva Reddy .freeze = sxgbe_platform_freeze,
2141edb9ca6SSiva Reddy .thaw = sxgbe_platform_restore,
2151edb9ca6SSiva Reddy .restore = sxgbe_platform_restore,
2161edb9ca6SSiva Reddy };
2171edb9ca6SSiva Reddy #else
2181edb9ca6SSiva Reddy static const struct dev_pm_ops sxgbe_platform_pm_ops;
2191edb9ca6SSiva Reddy #endif /* CONFIG_PM */
2201edb9ca6SSiva Reddy
2211edb9ca6SSiva Reddy static const struct of_device_id sxgbe_dt_ids[] = {
2221edb9ca6SSiva Reddy { .compatible = "samsung,sxgbe-v2.0a"},
2231edb9ca6SSiva Reddy { /* sentinel */ }
2241edb9ca6SSiva Reddy };
2251edb9ca6SSiva Reddy MODULE_DEVICE_TABLE(of, sxgbe_dt_ids);
22640b92cadSByungho An
2271edb9ca6SSiva Reddy static struct platform_driver sxgbe_platform_driver = {
2281edb9ca6SSiva Reddy .probe = sxgbe_platform_probe,
2291edb9ca6SSiva Reddy .remove = sxgbe_platform_remove,
2301edb9ca6SSiva Reddy .driver = {
2311edb9ca6SSiva Reddy .name = SXGBE_RESOURCE_NAME,
232*7f319fe4SKrzysztof Kozlowski .pm = &sxgbe_platform_pm_ops,
2331edb9ca6SSiva Reddy .of_match_table = sxgbe_dt_ids,
2341edb9ca6SSiva Reddy },
2351edb9ca6SSiva Reddy };
2361edb9ca6SSiva Reddy
sxgbe_register_platform(void)2371edb9ca6SSiva Reddy int sxgbe_register_platform(void)
2381edb9ca6SSiva Reddy {
2391edb9ca6SSiva Reddy int err;
2401edb9ca6SSiva Reddy
2411edb9ca6SSiva Reddy err = platform_driver_register(&sxgbe_platform_driver);
2421edb9ca6SSiva Reddy if (err)
2431edb9ca6SSiva Reddy pr_err("failed to register the platform driver\n");
2441edb9ca6SSiva Reddy
2451edb9ca6SSiva Reddy return err;
2461edb9ca6SSiva Reddy }
2471edb9ca6SSiva Reddy
sxgbe_unregister_platform(void)2481edb9ca6SSiva Reddy void sxgbe_unregister_platform(void)
2491edb9ca6SSiva Reddy {
2501edb9ca6SSiva Reddy platform_driver_unregister(&sxgbe_platform_driver);
251 }
252