Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020, Loongson Corporation
0003  */
0004 
0005 #include <linux/clk-provider.h>
0006 #include <linux/pci.h>
0007 #include <linux/dmi.h>
0008 #include <linux/device.h>
0009 #include <linux/of_irq.h>
0010 #include "stmmac.h"
0011 
0012 static int loongson_default_data(struct plat_stmmacenet_data *plat)
0013 {
0014     plat->clk_csr = 2;  /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
0015     plat->has_gmac = 1;
0016     plat->force_sf_dma_mode = 1;
0017 
0018     /* Set default value for multicast hash bins */
0019     plat->multicast_filter_bins = HASH_TABLE_SIZE;
0020 
0021     /* Set default value for unicast filter entries */
0022     plat->unicast_filter_entries = 1;
0023 
0024     /* Set the maxmtu to a default of JUMBO_LEN */
0025     plat->maxmtu = JUMBO_LEN;
0026 
0027     /* Set default number of RX and TX queues to use */
0028     plat->tx_queues_to_use = 1;
0029     plat->rx_queues_to_use = 1;
0030 
0031     /* Disable Priority config by default */
0032     plat->tx_queues_cfg[0].use_prio = false;
0033     plat->rx_queues_cfg[0].use_prio = false;
0034 
0035     /* Disable RX queues routing by default */
0036     plat->rx_queues_cfg[0].pkt_route = 0x0;
0037 
0038     /* Default to phy auto-detection */
0039     plat->phy_addr = -1;
0040 
0041     plat->dma_cfg->pbl = 32;
0042     plat->dma_cfg->pblx8 = true;
0043 
0044     plat->multicast_filter_bins = 256;
0045     return 0;
0046 }
0047 
0048 static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id)
0049 {
0050     struct plat_stmmacenet_data *plat;
0051     struct stmmac_resources res;
0052     struct device_node *np;
0053     int ret, i, phy_mode;
0054     bool mdio = false;
0055 
0056     np = dev_of_node(&pdev->dev);
0057 
0058     if (!np) {
0059         pr_info("dwmac_loongson_pci: No OF node\n");
0060         return -ENODEV;
0061     }
0062 
0063     if (!of_device_is_compatible(np, "loongson, pci-gmac")) {
0064         pr_info("dwmac_loongson_pci: Incompatible OF node\n");
0065         return -ENODEV;
0066     }
0067 
0068     plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
0069     if (!plat)
0070         return -ENOMEM;
0071 
0072     if (plat->mdio_node) {
0073         dev_err(&pdev->dev, "Found MDIO subnode\n");
0074         mdio = true;
0075     }
0076 
0077     if (mdio) {
0078         plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
0079                            sizeof(*plat->mdio_bus_data),
0080                            GFP_KERNEL);
0081         if (!plat->mdio_bus_data)
0082             return -ENOMEM;
0083         plat->mdio_bus_data->needs_reset = true;
0084     }
0085 
0086     plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL);
0087     if (!plat->dma_cfg)
0088         return -ENOMEM;
0089 
0090     /* Enable pci device */
0091     ret = pci_enable_device(pdev);
0092     if (ret) {
0093         dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__);
0094         return ret;
0095     }
0096 
0097     /* Get the base address of device */
0098     for (i = 0; i < PCI_STD_NUM_BARS; i++) {
0099         if (pci_resource_len(pdev, i) == 0)
0100             continue;
0101         ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
0102         if (ret)
0103             return ret;
0104         break;
0105     }
0106 
0107     plat->bus_id = of_alias_get_id(np, "ethernet");
0108     if (plat->bus_id < 0)
0109         plat->bus_id = pci_dev_id(pdev);
0110 
0111     phy_mode = device_get_phy_mode(&pdev->dev);
0112     if (phy_mode < 0) {
0113         dev_err(&pdev->dev, "phy_mode not found\n");
0114         return phy_mode;
0115     }
0116 
0117     plat->phy_interface = phy_mode;
0118     plat->interface = PHY_INTERFACE_MODE_GMII;
0119 
0120     pci_set_master(pdev);
0121 
0122     loongson_default_data(plat);
0123     pci_enable_msi(pdev);
0124     memset(&res, 0, sizeof(res));
0125     res.addr = pcim_iomap_table(pdev)[0];
0126 
0127     res.irq = of_irq_get_byname(np, "macirq");
0128     if (res.irq < 0) {
0129         dev_err(&pdev->dev, "IRQ macirq not found\n");
0130         ret = -ENODEV;
0131     }
0132 
0133     res.wol_irq = of_irq_get_byname(np, "eth_wake_irq");
0134     if (res.wol_irq < 0) {
0135         dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n");
0136         res.wol_irq = res.irq;
0137     }
0138 
0139     res.lpi_irq = of_irq_get_byname(np, "eth_lpi");
0140     if (res.lpi_irq < 0) {
0141         dev_err(&pdev->dev, "IRQ eth_lpi not found\n");
0142         ret = -ENODEV;
0143     }
0144 
0145     return stmmac_dvr_probe(&pdev->dev, plat, &res);
0146 }
0147 
0148 static void loongson_dwmac_remove(struct pci_dev *pdev)
0149 {
0150     int i;
0151 
0152     stmmac_dvr_remove(&pdev->dev);
0153 
0154     for (i = 0; i < PCI_STD_NUM_BARS; i++) {
0155         if (pci_resource_len(pdev, i) == 0)
0156             continue;
0157         pcim_iounmap_regions(pdev, BIT(i));
0158         break;
0159     }
0160 
0161     pci_disable_device(pdev);
0162 }
0163 
0164 static int __maybe_unused loongson_dwmac_suspend(struct device *dev)
0165 {
0166     struct pci_dev *pdev = to_pci_dev(dev);
0167     int ret;
0168 
0169     ret = stmmac_suspend(dev);
0170     if (ret)
0171         return ret;
0172 
0173     ret = pci_save_state(pdev);
0174     if (ret)
0175         return ret;
0176 
0177     pci_disable_device(pdev);
0178     pci_wake_from_d3(pdev, true);
0179     return 0;
0180 }
0181 
0182 static int __maybe_unused loongson_dwmac_resume(struct device *dev)
0183 {
0184     struct pci_dev *pdev = to_pci_dev(dev);
0185     int ret;
0186 
0187     pci_restore_state(pdev);
0188     pci_set_power_state(pdev, PCI_D0);
0189 
0190     ret = pci_enable_device(pdev);
0191     if (ret)
0192         return ret;
0193 
0194     pci_set_master(pdev);
0195 
0196     return stmmac_resume(dev);
0197 }
0198 
0199 static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend,
0200              loongson_dwmac_resume);
0201 
0202 static const struct pci_device_id loongson_dwmac_id_table[] = {
0203     { PCI_VDEVICE(LOONGSON, 0x7a03) },
0204     {}
0205 };
0206 MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table);
0207 
0208 static struct pci_driver loongson_dwmac_driver = {
0209     .name = "dwmac-loongson-pci",
0210     .id_table = loongson_dwmac_id_table,
0211     .probe = loongson_dwmac_probe,
0212     .remove = loongson_dwmac_remove,
0213     .driver = {
0214         .pm = &loongson_dwmac_pm_ops,
0215     },
0216 };
0217 
0218 module_pci_driver(loongson_dwmac_driver);
0219 
0220 MODULE_DESCRIPTION("Loongson DWMAC PCI driver");
0221 MODULE_AUTHOR("Qing Zhang <zhangqing@loongson.cn>");
0222 MODULE_LICENSE("GPL v2");