1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2020, Loongson Corporation 3 */ 4 5 #include <linux/clk-provider.h> 6 #include <linux/pci.h> 7 #include <linux/dmi.h> 8 #include <linux/device.h> 9 #include <linux/of_irq.h> 10 #include "stmmac.h" 11 12 static int loongson_default_data(struct plat_stmmacenet_data *plat) 13 { 14 plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ 15 plat->has_gmac = 1; 16 plat->force_sf_dma_mode = 1; 17 18 /* Set default value for multicast hash bins */ 19 plat->multicast_filter_bins = HASH_TABLE_SIZE; 20 21 /* Set default value for unicast filter entries */ 22 plat->unicast_filter_entries = 1; 23 24 /* Set the maxmtu to a default of JUMBO_LEN */ 25 plat->maxmtu = JUMBO_LEN; 26 27 /* Set default number of RX and TX queues to use */ 28 plat->tx_queues_to_use = 1; 29 plat->rx_queues_to_use = 1; 30 31 /* Disable Priority config by default */ 32 plat->tx_queues_cfg[0].use_prio = false; 33 plat->rx_queues_cfg[0].use_prio = false; 34 35 /* Disable RX queues routing by default */ 36 plat->rx_queues_cfg[0].pkt_route = 0x0; 37 38 plat->clk_ref_rate = 125000000; 39 plat->clk_ptp_rate = 125000000; 40 41 /* Default to phy auto-detection */ 42 plat->phy_addr = -1; 43 44 plat->dma_cfg->pbl = 32; 45 plat->dma_cfg->pblx8 = true; 46 47 plat->multicast_filter_bins = 256; 48 return 0; 49 } 50 51 static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) 52 { 53 struct plat_stmmacenet_data *plat; 54 struct stmmac_resources res; 55 struct device_node *np; 56 int ret, i, phy_mode; 57 58 np = dev_of_node(&pdev->dev); 59 60 if (!np) { 61 pr_info("dwmac_loongson_pci: No OF node\n"); 62 return -ENODEV; 63 } 64 65 plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); 66 if (!plat) 67 return -ENOMEM; 68 69 plat->mdio_bus_data = devm_kzalloc(&pdev->dev, 70 sizeof(*plat->mdio_bus_data), 71 GFP_KERNEL); 72 if (!plat->mdio_bus_data) 73 return -ENOMEM; 74 75 plat->mdio_node = of_get_child_by_name(np, "mdio"); 76 if (plat->mdio_node) { 77 dev_info(&pdev->dev, "Found MDIO subnode\n"); 78 plat->mdio_bus_data->needs_reset = true; 79 } 80 81 plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL); 82 if (!plat->dma_cfg) { 83 ret = -ENOMEM; 84 goto err_put_node; 85 } 86 87 /* Enable pci device */ 88 ret = pci_enable_device(pdev); 89 if (ret) { 90 dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); 91 goto err_put_node; 92 } 93 94 /* Get the base address of device */ 95 for (i = 0; i < PCI_STD_NUM_BARS; i++) { 96 if (pci_resource_len(pdev, i) == 0) 97 continue; 98 ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); 99 if (ret) 100 goto err_disable_device; 101 break; 102 } 103 104 plat->bus_id = of_alias_get_id(np, "ethernet"); 105 if (plat->bus_id < 0) 106 plat->bus_id = pci_dev_id(pdev); 107 108 phy_mode = device_get_phy_mode(&pdev->dev); 109 if (phy_mode < 0) { 110 dev_err(&pdev->dev, "phy_mode not found\n"); 111 ret = phy_mode; 112 goto err_disable_device; 113 } 114 115 plat->phy_interface = phy_mode; 116 plat->mac_interface = PHY_INTERFACE_MODE_GMII; 117 118 pci_set_master(pdev); 119 120 loongson_default_data(plat); 121 pci_enable_msi(pdev); 122 memset(&res, 0, sizeof(res)); 123 res.addr = pcim_iomap_table(pdev)[0]; 124 125 res.irq = of_irq_get_byname(np, "macirq"); 126 if (res.irq < 0) { 127 dev_err(&pdev->dev, "IRQ macirq not found\n"); 128 ret = -ENODEV; 129 goto err_disable_msi; 130 } 131 132 res.wol_irq = of_irq_get_byname(np, "eth_wake_irq"); 133 if (res.wol_irq < 0) { 134 dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n"); 135 res.wol_irq = res.irq; 136 } 137 138 res.lpi_irq = of_irq_get_byname(np, "eth_lpi"); 139 if (res.lpi_irq < 0) { 140 dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); 141 ret = -ENODEV; 142 goto err_disable_msi; 143 } 144 145 ret = stmmac_dvr_probe(&pdev->dev, plat, &res); 146 if (ret) 147 goto err_disable_msi; 148 149 return ret; 150 151 err_disable_msi: 152 pci_disable_msi(pdev); 153 err_disable_device: 154 pci_disable_device(pdev); 155 err_put_node: 156 of_node_put(plat->mdio_node); 157 return ret; 158 } 159 160 static void loongson_dwmac_remove(struct pci_dev *pdev) 161 { 162 struct net_device *ndev = dev_get_drvdata(&pdev->dev); 163 struct stmmac_priv *priv = netdev_priv(ndev); 164 int i; 165 166 of_node_put(priv->plat->mdio_node); 167 stmmac_dvr_remove(&pdev->dev); 168 169 for (i = 0; i < PCI_STD_NUM_BARS; i++) { 170 if (pci_resource_len(pdev, i) == 0) 171 continue; 172 pcim_iounmap_regions(pdev, BIT(i)); 173 break; 174 } 175 176 pci_disable_msi(pdev); 177 pci_disable_device(pdev); 178 } 179 180 static int __maybe_unused loongson_dwmac_suspend(struct device *dev) 181 { 182 struct pci_dev *pdev = to_pci_dev(dev); 183 int ret; 184 185 ret = stmmac_suspend(dev); 186 if (ret) 187 return ret; 188 189 ret = pci_save_state(pdev); 190 if (ret) 191 return ret; 192 193 pci_disable_device(pdev); 194 pci_wake_from_d3(pdev, true); 195 return 0; 196 } 197 198 static int __maybe_unused loongson_dwmac_resume(struct device *dev) 199 { 200 struct pci_dev *pdev = to_pci_dev(dev); 201 int ret; 202 203 pci_restore_state(pdev); 204 pci_set_power_state(pdev, PCI_D0); 205 206 ret = pci_enable_device(pdev); 207 if (ret) 208 return ret; 209 210 pci_set_master(pdev); 211 212 return stmmac_resume(dev); 213 } 214 215 static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend, 216 loongson_dwmac_resume); 217 218 static const struct pci_device_id loongson_dwmac_id_table[] = { 219 { PCI_VDEVICE(LOONGSON, 0x7a03) }, 220 {} 221 }; 222 MODULE_DEVICE_TABLE(pci, loongson_dwmac_id_table); 223 224 static struct pci_driver loongson_dwmac_driver = { 225 .name = "dwmac-loongson-pci", 226 .id_table = loongson_dwmac_id_table, 227 .probe = loongson_dwmac_probe, 228 .remove = loongson_dwmac_remove, 229 .driver = { 230 .pm = &loongson_dwmac_pm_ops, 231 }, 232 }; 233 234 module_pci_driver(loongson_dwmac_driver); 235 236 MODULE_DESCRIPTION("Loongson DWMAC PCI driver"); 237 MODULE_AUTHOR("Qing Zhang <zhangqing@loongson.cn>"); 238 MODULE_LICENSE("GPL v2"); 239