hwif.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /*
  3. * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
  4. * stmmac HW Interface Handling
  5. */
  6. #include "common.h"
  7. #include "stmmac.h"
  8. #include "stmmac_ptp.h"
  9. static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
  10. {
  11. u32 reg = readl(priv->ioaddr + id_reg);
  12. if (!reg) {
  13. dev_info(priv->device, "Version ID not available\n");
  14. return 0x0;
  15. }
  16. dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n",
  17. (unsigned int)(reg & GENMASK(15, 8)) >> 8,
  18. (unsigned int)(reg & GENMASK(7, 0)));
  19. return reg & GENMASK(7, 0);
  20. }
  21. static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
  22. {
  23. struct mac_device_info *mac = priv->hw;
  24. if (priv->chain_mode) {
  25. dev_info(priv->device, "Chain mode enabled\n");
  26. priv->mode = STMMAC_CHAIN_MODE;
  27. mac->mode = &chain_mode_ops;
  28. } else {
  29. dev_info(priv->device, "Ring mode enabled\n");
  30. priv->mode = STMMAC_RING_MODE;
  31. mac->mode = &ring_mode_ops;
  32. }
  33. }
  34. static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
  35. {
  36. struct mac_device_info *mac = priv->hw;
  37. if (priv->plat->enh_desc) {
  38. dev_info(priv->device, "Enhanced/Alternate descriptors\n");
  39. /* GMAC older than 3.50 has no extended descriptors */
  40. if (priv->synopsys_id >= DWMAC_CORE_3_50) {
  41. dev_info(priv->device, "Enabled extended descriptors\n");
  42. priv->extend_desc = 1;
  43. } else {
  44. dev_warn(priv->device, "Extended descriptors not supported\n");
  45. }
  46. mac->desc = &enh_desc_ops;
  47. } else {
  48. dev_info(priv->device, "Normal descriptors\n");
  49. mac->desc = &ndesc_ops;
  50. }
  51. stmmac_dwmac_mode_quirk(priv);
  52. return 0;
  53. }
  54. static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
  55. {
  56. stmmac_dwmac_mode_quirk(priv);
  57. return 0;
  58. }
  59. static const struct stmmac_hwif_entry {
  60. bool gmac;
  61. bool gmac4;
  62. u32 min_id;
  63. const struct stmmac_regs_off regs;
  64. const void *desc;
  65. const void *dma;
  66. const void *mac;
  67. const void *hwtimestamp;
  68. const void *mode;
  69. const void *tc;
  70. int (*setup)(struct stmmac_priv *priv);
  71. int (*quirks)(struct stmmac_priv *priv);
  72. } stmmac_hw[] = {
  73. /* NOTE: New HW versions shall go to the end of this table */
  74. {
  75. .gmac = false,
  76. .gmac4 = false,
  77. .min_id = 0,
  78. .regs = {
  79. .ptp_off = PTP_GMAC3_X_OFFSET,
  80. .mmc_off = MMC_GMAC3_X_OFFSET,
  81. },
  82. .desc = NULL,
  83. .dma = &dwmac100_dma_ops,
  84. .mac = &dwmac100_ops,
  85. .hwtimestamp = &stmmac_ptp,
  86. .mode = NULL,
  87. .tc = NULL,
  88. .setup = dwmac100_setup,
  89. .quirks = stmmac_dwmac1_quirks,
  90. }, {
  91. .gmac = true,
  92. .gmac4 = false,
  93. .min_id = 0,
  94. .regs = {
  95. .ptp_off = PTP_GMAC3_X_OFFSET,
  96. .mmc_off = MMC_GMAC3_X_OFFSET,
  97. },
  98. .desc = NULL,
  99. .dma = &dwmac1000_dma_ops,
  100. .mac = &dwmac1000_ops,
  101. .hwtimestamp = &stmmac_ptp,
  102. .mode = NULL,
  103. .tc = NULL,
  104. .setup = dwmac1000_setup,
  105. .quirks = stmmac_dwmac1_quirks,
  106. }, {
  107. .gmac = false,
  108. .gmac4 = true,
  109. .min_id = 0,
  110. .regs = {
  111. .ptp_off = PTP_GMAC4_OFFSET,
  112. .mmc_off = MMC_GMAC4_OFFSET,
  113. },
  114. .desc = &dwmac4_desc_ops,
  115. .dma = &dwmac4_dma_ops,
  116. .mac = &dwmac4_ops,
  117. .hwtimestamp = &stmmac_ptp,
  118. .mode = NULL,
  119. .tc = NULL,
  120. .setup = dwmac4_setup,
  121. .quirks = stmmac_dwmac4_quirks,
  122. }, {
  123. .gmac = false,
  124. .gmac4 = true,
  125. .min_id = DWMAC_CORE_4_00,
  126. .regs = {
  127. .ptp_off = PTP_GMAC4_OFFSET,
  128. .mmc_off = MMC_GMAC4_OFFSET,
  129. },
  130. .desc = &dwmac4_desc_ops,
  131. .dma = &dwmac4_dma_ops,
  132. .mac = &dwmac410_ops,
  133. .hwtimestamp = &stmmac_ptp,
  134. .mode = &dwmac4_ring_mode_ops,
  135. .tc = NULL,
  136. .setup = dwmac4_setup,
  137. .quirks = NULL,
  138. }, {
  139. .gmac = false,
  140. .gmac4 = true,
  141. .min_id = DWMAC_CORE_4_10,
  142. .regs = {
  143. .ptp_off = PTP_GMAC4_OFFSET,
  144. .mmc_off = MMC_GMAC4_OFFSET,
  145. },
  146. .desc = &dwmac4_desc_ops,
  147. .dma = &dwmac410_dma_ops,
  148. .mac = &dwmac410_ops,
  149. .hwtimestamp = &stmmac_ptp,
  150. .mode = &dwmac4_ring_mode_ops,
  151. .tc = NULL,
  152. .setup = dwmac4_setup,
  153. .quirks = NULL,
  154. }, {
  155. .gmac = false,
  156. .gmac4 = true,
  157. .min_id = DWMAC_CORE_5_10,
  158. .regs = {
  159. .ptp_off = PTP_GMAC4_OFFSET,
  160. .mmc_off = MMC_GMAC4_OFFSET,
  161. },
  162. .desc = &dwmac4_desc_ops,
  163. .dma = &dwmac410_dma_ops,
  164. .mac = &dwmac510_ops,
  165. .hwtimestamp = &stmmac_ptp,
  166. .mode = &dwmac4_ring_mode_ops,
  167. .tc = &dwmac510_tc_ops,
  168. .setup = dwmac4_setup,
  169. .quirks = NULL,
  170. }
  171. };
  172. int stmmac_hwif_init(struct stmmac_priv *priv)
  173. {
  174. bool needs_gmac4 = priv->plat->has_gmac4;
  175. bool needs_gmac = priv->plat->has_gmac;
  176. const struct stmmac_hwif_entry *entry;
  177. struct mac_device_info *mac;
  178. bool needs_setup = true;
  179. int i, ret;
  180. u32 id;
  181. if (needs_gmac) {
  182. id = stmmac_get_id(priv, GMAC_VERSION);
  183. } else if (needs_gmac4) {
  184. id = stmmac_get_id(priv, GMAC4_VERSION);
  185. } else {
  186. id = 0;
  187. }
  188. /* Save ID for later use */
  189. priv->synopsys_id = id;
  190. /* Lets assume some safe values first */
  191. priv->ptpaddr = priv->ioaddr +
  192. (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
  193. priv->mmcaddr = priv->ioaddr +
  194. (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
  195. /* Check for HW specific setup first */
  196. if (priv->plat->setup) {
  197. mac = priv->plat->setup(priv);
  198. needs_setup = false;
  199. } else {
  200. mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
  201. }
  202. if (!mac)
  203. return -ENOMEM;
  204. /* Fallback to generic HW */
  205. for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
  206. entry = &stmmac_hw[i];
  207. if (needs_gmac ^ entry->gmac)
  208. continue;
  209. if (needs_gmac4 ^ entry->gmac4)
  210. continue;
  211. /* Use synopsys_id var because some setups can override this */
  212. if (priv->synopsys_id < entry->min_id)
  213. continue;
  214. /* Only use generic HW helpers if needed */
  215. mac->desc = mac->desc ? : entry->desc;
  216. mac->dma = mac->dma ? : entry->dma;
  217. mac->mac = mac->mac ? : entry->mac;
  218. mac->ptp = mac->ptp ? : entry->hwtimestamp;
  219. mac->mode = mac->mode ? : entry->mode;
  220. mac->tc = mac->tc ? : entry->tc;
  221. priv->hw = mac;
  222. priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
  223. priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
  224. /* Entry found */
  225. if (needs_setup) {
  226. ret = entry->setup(priv);
  227. if (ret)
  228. return ret;
  229. }
  230. /* Save quirks, if needed for posterior use */
  231. priv->hwif_quirks = entry->quirks;
  232. return 0;
  233. }
  234. dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
  235. id, needs_gmac, needs_gmac4);
  236. return -EINVAL;
  237. }