dwmac-oxnas.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Oxford Semiconductor OXNAS DWMAC glue layer
  4. *
  5. * Copyright (C) 2016 Neil Armstrong <[email protected]>
  6. * Copyright (C) 2014 Daniel Golle <[email protected]>
  7. * Copyright (C) 2013 Ma Haijun <[email protected]>
  8. * Copyright (C) 2012 John Crispin <[email protected]>
  9. */
  10. #include <linux/device.h>
  11. #include <linux/io.h>
  12. #include <linux/module.h>
  13. #include <linux/of.h>
  14. #include <linux/of_device.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/regmap.h>
  17. #include <linux/mfd/syscon.h>
  18. #include <linux/stmmac.h>
  19. #include "stmmac_platform.h"
  20. /* System Control regmap offsets */
  21. #define OXNAS_DWMAC_CTRL_REGOFFSET 0x78
  22. #define OXNAS_DWMAC_DELAY_REGOFFSET 0x100
  23. /* Control Register */
  24. #define DWMAC_CKEN_RX_IN 14
  25. #define DWMAC_CKEN_RXN_OUT 13
  26. #define DWMAC_CKEN_RX_OUT 12
  27. #define DWMAC_CKEN_TX_IN 10
  28. #define DWMAC_CKEN_TXN_OUT 9
  29. #define DWMAC_CKEN_TX_OUT 8
  30. #define DWMAC_RX_SOURCE 7
  31. #define DWMAC_TX_SOURCE 6
  32. #define DWMAC_LOW_TX_SOURCE 4
  33. #define DWMAC_AUTO_TX_SOURCE 3
  34. #define DWMAC_RGMII 2
  35. #define DWMAC_SIMPLE_MUX 1
  36. #define DWMAC_CKEN_GTX 0
  37. /* Delay register */
  38. #define DWMAC_TX_VARDELAY_SHIFT 0
  39. #define DWMAC_TXN_VARDELAY_SHIFT 8
  40. #define DWMAC_RX_VARDELAY_SHIFT 16
  41. #define DWMAC_RXN_VARDELAY_SHIFT 24
  42. #define DWMAC_TX_VARDELAY(d) ((d) << DWMAC_TX_VARDELAY_SHIFT)
  43. #define DWMAC_TXN_VARDELAY(d) ((d) << DWMAC_TXN_VARDELAY_SHIFT)
  44. #define DWMAC_RX_VARDELAY(d) ((d) << DWMAC_RX_VARDELAY_SHIFT)
  45. #define DWMAC_RXN_VARDELAY(d) ((d) << DWMAC_RXN_VARDELAY_SHIFT)
  46. struct oxnas_dwmac;
  47. struct oxnas_dwmac_data {
  48. int (*setup)(struct oxnas_dwmac *dwmac);
  49. };
  50. struct oxnas_dwmac {
  51. struct device *dev;
  52. struct clk *clk;
  53. struct regmap *regmap;
  54. const struct oxnas_dwmac_data *data;
  55. };
  56. static int oxnas_dwmac_setup_ox810se(struct oxnas_dwmac *dwmac)
  57. {
  58. unsigned int value;
  59. int ret;
  60. ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
  61. if (ret < 0)
  62. return ret;
  63. /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
  64. value |= BIT(DWMAC_CKEN_GTX) |
  65. /* Use simple mux for 25/125 Mhz clock switching */
  66. BIT(DWMAC_SIMPLE_MUX);
  67. regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
  68. return 0;
  69. }
  70. static int oxnas_dwmac_setup_ox820(struct oxnas_dwmac *dwmac)
  71. {
  72. unsigned int value;
  73. int ret;
  74. ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
  75. if (ret < 0)
  76. return ret;
  77. /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
  78. value |= BIT(DWMAC_CKEN_GTX) |
  79. /* Use simple mux for 25/125 Mhz clock switching */
  80. BIT(DWMAC_SIMPLE_MUX) |
  81. /* set auto switch tx clock source */
  82. BIT(DWMAC_AUTO_TX_SOURCE) |
  83. /* enable tx & rx vardelay */
  84. BIT(DWMAC_CKEN_TX_OUT) |
  85. BIT(DWMAC_CKEN_TXN_OUT) |
  86. BIT(DWMAC_CKEN_TX_IN) |
  87. BIT(DWMAC_CKEN_RX_OUT) |
  88. BIT(DWMAC_CKEN_RXN_OUT) |
  89. BIT(DWMAC_CKEN_RX_IN);
  90. regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
  91. /* set tx & rx vardelay */
  92. value = DWMAC_TX_VARDELAY(4) |
  93. DWMAC_TXN_VARDELAY(2) |
  94. DWMAC_RX_VARDELAY(10) |
  95. DWMAC_RXN_VARDELAY(8);
  96. regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
  97. return 0;
  98. }
  99. static int oxnas_dwmac_init(struct platform_device *pdev, void *priv)
  100. {
  101. struct oxnas_dwmac *dwmac = priv;
  102. int ret;
  103. /* Reset HW here before changing the glue configuration */
  104. ret = device_reset(dwmac->dev);
  105. if (ret)
  106. return ret;
  107. ret = clk_prepare_enable(dwmac->clk);
  108. if (ret)
  109. return ret;
  110. ret = dwmac->data->setup(dwmac);
  111. if (ret)
  112. clk_disable_unprepare(dwmac->clk);
  113. return ret;
  114. }
  115. static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv)
  116. {
  117. struct oxnas_dwmac *dwmac = priv;
  118. clk_disable_unprepare(dwmac->clk);
  119. }
  120. static int oxnas_dwmac_probe(struct platform_device *pdev)
  121. {
  122. struct plat_stmmacenet_data *plat_dat;
  123. struct stmmac_resources stmmac_res;
  124. struct oxnas_dwmac *dwmac;
  125. int ret;
  126. ret = stmmac_get_platform_resources(pdev, &stmmac_res);
  127. if (ret)
  128. return ret;
  129. plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
  130. if (IS_ERR(plat_dat))
  131. return PTR_ERR(plat_dat);
  132. dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
  133. if (!dwmac) {
  134. ret = -ENOMEM;
  135. goto err_remove_config_dt;
  136. }
  137. dwmac->data = (const struct oxnas_dwmac_data *)of_device_get_match_data(&pdev->dev);
  138. if (!dwmac->data) {
  139. ret = -EINVAL;
  140. goto err_remove_config_dt;
  141. }
  142. dwmac->dev = &pdev->dev;
  143. plat_dat->bsp_priv = dwmac;
  144. plat_dat->init = oxnas_dwmac_init;
  145. plat_dat->exit = oxnas_dwmac_exit;
  146. dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
  147. "oxsemi,sys-ctrl");
  148. if (IS_ERR(dwmac->regmap)) {
  149. dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
  150. ret = PTR_ERR(dwmac->regmap);
  151. goto err_remove_config_dt;
  152. }
  153. dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
  154. if (IS_ERR(dwmac->clk)) {
  155. ret = PTR_ERR(dwmac->clk);
  156. goto err_remove_config_dt;
  157. }
  158. ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv);
  159. if (ret)
  160. goto err_remove_config_dt;
  161. ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
  162. if (ret)
  163. goto err_dwmac_exit;
  164. return 0;
  165. err_dwmac_exit:
  166. oxnas_dwmac_exit(pdev, plat_dat->bsp_priv);
  167. err_remove_config_dt:
  168. stmmac_remove_config_dt(pdev, plat_dat);
  169. return ret;
  170. }
  171. static const struct oxnas_dwmac_data ox810se_dwmac_data = {
  172. .setup = oxnas_dwmac_setup_ox810se,
  173. };
  174. static const struct oxnas_dwmac_data ox820_dwmac_data = {
  175. .setup = oxnas_dwmac_setup_ox820,
  176. };
  177. static const struct of_device_id oxnas_dwmac_match[] = {
  178. {
  179. .compatible = "oxsemi,ox810se-dwmac",
  180. .data = &ox810se_dwmac_data,
  181. },
  182. {
  183. .compatible = "oxsemi,ox820-dwmac",
  184. .data = &ox820_dwmac_data,
  185. },
  186. { }
  187. };
  188. MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
  189. static struct platform_driver oxnas_dwmac_driver = {
  190. .probe = oxnas_dwmac_probe,
  191. .remove = stmmac_pltfr_remove,
  192. .driver = {
  193. .name = "oxnas-dwmac",
  194. .pm = &stmmac_pltfr_pm_ops,
  195. .of_match_table = oxnas_dwmac_match,
  196. },
  197. };
  198. module_platform_driver(oxnas_dwmac_driver);
  199. MODULE_AUTHOR("Neil Armstrong <[email protected]>");
  200. MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer");
  201. MODULE_LICENSE("GPL v2");