dwmac_socfpga.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2018 Marek Vasut <marex@denx.de>
  4. *
  5. * Altera SoCFPGA EMAC extras
  6. */
  7. #include <common.h>
  8. #include <asm/io.h>
  9. #include <dm.h>
  10. #include <clk.h>
  11. #include <phy.h>
  12. #include <regmap.h>
  13. #include <reset.h>
  14. #include <syscon.h>
  15. #include "designware.h"
  16. #include <asm/arch/system_manager.h>
  17. enum dwmac_type {
  18. DWMAC_SOCFPGA_GEN5 = 0,
  19. DWMAC_SOCFPGA_ARRIA10,
  20. DWMAC_SOCFPGA_STRATIX10,
  21. };
  22. struct dwmac_socfpga_platdata {
  23. struct dw_eth_pdata dw_eth_pdata;
  24. enum dwmac_type type;
  25. void *phy_intf;
  26. };
  27. static int dwmac_socfpga_ofdata_to_platdata(struct udevice *dev)
  28. {
  29. struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
  30. struct regmap *regmap;
  31. struct ofnode_phandle_args args;
  32. void *range;
  33. int ret;
  34. ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL,
  35. 2, 0, &args);
  36. if (ret) {
  37. dev_err(dev, "Failed to get syscon: %d\n", ret);
  38. return ret;
  39. }
  40. if (args.args_count != 2) {
  41. dev_err(dev, "Invalid number of syscon args\n");
  42. return -EINVAL;
  43. }
  44. regmap = syscon_node_to_regmap(args.node);
  45. if (IS_ERR(regmap)) {
  46. ret = PTR_ERR(regmap);
  47. dev_err(dev, "Failed to get regmap: %d\n", ret);
  48. return ret;
  49. }
  50. range = regmap_get_range(regmap, 0);
  51. if (!range) {
  52. dev_err(dev, "Failed to get regmap range\n");
  53. return -ENOMEM;
  54. }
  55. pdata->phy_intf = range + args.args[0];
  56. /*
  57. * Sadly, the Altera DT bindings don't have SoC-specific compatibles,
  58. * so we have to guesstimate which SoC we are running on from the
  59. * DWMAC version. Luckily, Altera at least updated the DWMAC with
  60. * each SoC.
  61. */
  62. if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.70a"))
  63. pdata->type = DWMAC_SOCFPGA_GEN5;
  64. if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.72a"))
  65. pdata->type = DWMAC_SOCFPGA_ARRIA10;
  66. if (ofnode_device_is_compatible(dev->node, "snps,dwmac-3.74a"))
  67. pdata->type = DWMAC_SOCFPGA_STRATIX10;
  68. return designware_eth_ofdata_to_platdata(dev);
  69. }
  70. static int dwmac_socfpga_probe(struct udevice *dev)
  71. {
  72. struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
  73. struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata;
  74. struct reset_ctl_bulk reset_bulk;
  75. int ret;
  76. u8 modereg;
  77. if (pdata->type == DWMAC_SOCFPGA_ARRIA10) {
  78. switch (edata->phy_interface) {
  79. case PHY_INTERFACE_MODE_MII:
  80. case PHY_INTERFACE_MODE_GMII:
  81. modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
  82. break;
  83. case PHY_INTERFACE_MODE_RMII:
  84. modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII;
  85. break;
  86. case PHY_INTERFACE_MODE_RGMII:
  87. modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
  88. break;
  89. default:
  90. dev_err(dev, "Unsupported PHY mode\n");
  91. return -EINVAL;
  92. }
  93. ret = reset_get_bulk(dev, &reset_bulk);
  94. if (ret) {
  95. dev_err(dev, "Failed to get reset: %d\n", ret);
  96. return ret;
  97. }
  98. reset_assert_bulk(&reset_bulk);
  99. clrsetbits_le32(pdata->phy_intf,
  100. SYSMGR_EMACGRP_CTRL_PHYSEL_MASK,
  101. modereg);
  102. reset_release_bulk(&reset_bulk);
  103. }
  104. return designware_eth_probe(dev);
  105. }
  106. static const struct udevice_id dwmac_socfpga_ids[] = {
  107. { .compatible = "altr,socfpga-stmmac" },
  108. { }
  109. };
  110. U_BOOT_DRIVER(dwmac_socfpga) = {
  111. .name = "dwmac_socfpga",
  112. .id = UCLASS_ETH,
  113. .of_match = dwmac_socfpga_ids,
  114. .ofdata_to_platdata = dwmac_socfpga_ofdata_to_platdata,
  115. .probe = dwmac_socfpga_probe,
  116. .ops = &designware_eth_ops,
  117. .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
  118. .platdata_auto_alloc_size = sizeof(struct dwmac_socfpga_platdata),
  119. .flags = DM_FLAG_ALLOC_PRIV_DMA,
  120. };