dwmac-loongson.c 5.5 KB

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