dwmac-oxnas.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. * Oxford Semiconductor OXNAS DWMAC glue layer
  3. *
  4. * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
  5. * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
  6. * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
  7. * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <linux/device.h>
  17. #include <linux/io.h>
  18. #include <linux/module.h>
  19. #include <linux/of.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/regmap.h>
  22. #include <linux/mfd/syscon.h>
  23. #include <linux/stmmac.h>
  24. #include "stmmac_platform.h"
  25. /* System Control regmap offsets */
  26. #define OXNAS_DWMAC_CTRL_REGOFFSET 0x78
  27. #define OXNAS_DWMAC_DELAY_REGOFFSET 0x100
  28. /* Control Register */
  29. #define DWMAC_CKEN_RX_IN 14
  30. #define DWMAC_CKEN_RXN_OUT 13
  31. #define DWMAC_CKEN_RX_OUT 12
  32. #define DWMAC_CKEN_TX_IN 10
  33. #define DWMAC_CKEN_TXN_OUT 9
  34. #define DWMAC_CKEN_TX_OUT 8
  35. #define DWMAC_RX_SOURCE 7
  36. #define DWMAC_TX_SOURCE 6
  37. #define DWMAC_LOW_TX_SOURCE 4
  38. #define DWMAC_AUTO_TX_SOURCE 3
  39. #define DWMAC_RGMII 2
  40. #define DWMAC_SIMPLE_MUX 1
  41. #define DWMAC_CKEN_GTX 0
  42. /* Delay register */
  43. #define DWMAC_TX_VARDELAY_SHIFT 0
  44. #define DWMAC_TXN_VARDELAY_SHIFT 8
  45. #define DWMAC_RX_VARDELAY_SHIFT 16
  46. #define DWMAC_RXN_VARDELAY_SHIFT 24
  47. #define DWMAC_TX_VARDELAY(d) ((d) << DWMAC_TX_VARDELAY_SHIFT)
  48. #define DWMAC_TXN_VARDELAY(d) ((d) << DWMAC_TXN_VARDELAY_SHIFT)
  49. #define DWMAC_RX_VARDELAY(d) ((d) << DWMAC_RX_VARDELAY_SHIFT)
  50. #define DWMAC_RXN_VARDELAY(d) ((d) << DWMAC_RXN_VARDELAY_SHIFT)
  51. struct oxnas_dwmac {
  52. struct device *dev;
  53. struct clk *clk;
  54. struct regmap *regmap;
  55. };
  56. static int oxnas_dwmac_init(struct platform_device *pdev, void *priv)
  57. {
  58. struct oxnas_dwmac *dwmac = priv;
  59. unsigned int value;
  60. int ret;
  61. /* Reset HW here before changing the glue configuration */
  62. ret = device_reset(dwmac->dev);
  63. if (ret)
  64. return ret;
  65. ret = clk_prepare_enable(dwmac->clk);
  66. if (ret)
  67. return ret;
  68. ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
  69. if (ret < 0) {
  70. clk_disable_unprepare(dwmac->clk);
  71. return ret;
  72. }
  73. /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
  74. value |= BIT(DWMAC_CKEN_GTX) |
  75. /* Use simple mux for 25/125 Mhz clock switching */
  76. BIT(DWMAC_SIMPLE_MUX) |
  77. /* set auto switch tx clock source */
  78. BIT(DWMAC_AUTO_TX_SOURCE) |
  79. /* enable tx & rx vardelay */
  80. BIT(DWMAC_CKEN_TX_OUT) |
  81. BIT(DWMAC_CKEN_TXN_OUT) |
  82. BIT(DWMAC_CKEN_TX_IN) |
  83. BIT(DWMAC_CKEN_RX_OUT) |
  84. BIT(DWMAC_CKEN_RXN_OUT) |
  85. BIT(DWMAC_CKEN_RX_IN);
  86. regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
  87. /* set tx & rx vardelay */
  88. value = DWMAC_TX_VARDELAY(4) |
  89. DWMAC_TXN_VARDELAY(2) |
  90. DWMAC_RX_VARDELAY(10) |
  91. DWMAC_RXN_VARDELAY(8);
  92. regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
  93. return 0;
  94. }
  95. static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv)
  96. {
  97. struct oxnas_dwmac *dwmac = priv;
  98. clk_disable_unprepare(dwmac->clk);
  99. }
  100. static int oxnas_dwmac_probe(struct platform_device *pdev)
  101. {
  102. struct plat_stmmacenet_data *plat_dat;
  103. struct stmmac_resources stmmac_res;
  104. struct oxnas_dwmac *dwmac;
  105. int ret;
  106. ret = stmmac_get_platform_resources(pdev, &stmmac_res);
  107. if (ret)
  108. return ret;
  109. plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
  110. if (IS_ERR(plat_dat))
  111. return PTR_ERR(plat_dat);
  112. dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
  113. if (!dwmac) {
  114. ret = -ENOMEM;
  115. goto err_remove_config_dt;
  116. }
  117. dwmac->dev = &pdev->dev;
  118. plat_dat->bsp_priv = dwmac;
  119. plat_dat->init = oxnas_dwmac_init;
  120. plat_dat->exit = oxnas_dwmac_exit;
  121. dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
  122. "oxsemi,sys-ctrl");
  123. if (IS_ERR(dwmac->regmap)) {
  124. dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
  125. ret = PTR_ERR(dwmac->regmap);
  126. goto err_remove_config_dt;
  127. }
  128. dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
  129. if (IS_ERR(dwmac->clk)) {
  130. ret = PTR_ERR(dwmac->clk);
  131. goto err_remove_config_dt;
  132. }
  133. ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv);
  134. if (ret)
  135. goto err_remove_config_dt;
  136. ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
  137. if (ret)
  138. goto err_dwmac_exit;
  139. return 0;
  140. err_dwmac_exit:
  141. oxnas_dwmac_exit(pdev, plat_dat->bsp_priv);
  142. err_remove_config_dt:
  143. stmmac_remove_config_dt(pdev, plat_dat);
  144. return ret;
  145. }
  146. static const struct of_device_id oxnas_dwmac_match[] = {
  147. { .compatible = "oxsemi,ox820-dwmac" },
  148. { }
  149. };
  150. MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
  151. static struct platform_driver oxnas_dwmac_driver = {
  152. .probe = oxnas_dwmac_probe,
  153. .remove = stmmac_pltfr_remove,
  154. .driver = {
  155. .name = "oxnas-dwmac",
  156. .pm = &stmmac_pltfr_pm_ops,
  157. .of_match_table = oxnas_dwmac_match,
  158. },
  159. };
  160. module_platform_driver(oxnas_dwmac_driver);
  161. MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
  162. MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer");
  163. MODULE_LICENSE("GPL v2");