hwif.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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 u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg)
  22. {
  23. u32 reg = readl(priv->ioaddr + id_reg);
  24. if (!reg) {
  25. dev_info(priv->device, "Version ID not available\n");
  26. return 0x0;
  27. }
  28. return (reg & GENMASK(15, 8)) >> 8;
  29. }
  30. static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv)
  31. {
  32. struct mac_device_info *mac = priv->hw;
  33. if (priv->chain_mode) {
  34. dev_info(priv->device, "Chain mode enabled\n");
  35. priv->mode = STMMAC_CHAIN_MODE;
  36. mac->mode = &chain_mode_ops;
  37. } else {
  38. dev_info(priv->device, "Ring mode enabled\n");
  39. priv->mode = STMMAC_RING_MODE;
  40. mac->mode = &ring_mode_ops;
  41. }
  42. }
  43. static int stmmac_dwmac1_quirks(struct stmmac_priv *priv)
  44. {
  45. struct mac_device_info *mac = priv->hw;
  46. if (priv->plat->enh_desc) {
  47. dev_info(priv->device, "Enhanced/Alternate descriptors\n");
  48. /* GMAC older than 3.50 has no extended descriptors */
  49. if (priv->synopsys_id >= DWMAC_CORE_3_50) {
  50. dev_info(priv->device, "Enabled extended descriptors\n");
  51. priv->extend_desc = 1;
  52. } else {
  53. dev_warn(priv->device, "Extended descriptors not supported\n");
  54. }
  55. mac->desc = &enh_desc_ops;
  56. } else {
  57. dev_info(priv->device, "Normal descriptors\n");
  58. mac->desc = &ndesc_ops;
  59. }
  60. stmmac_dwmac_mode_quirk(priv);
  61. return 0;
  62. }
  63. static int stmmac_dwmac4_quirks(struct stmmac_priv *priv)
  64. {
  65. stmmac_dwmac_mode_quirk(priv);
  66. return 0;
  67. }
  68. static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv)
  69. {
  70. priv->hw->xlgmac = true;
  71. return 0;
  72. }
  73. static const struct stmmac_hwif_entry {
  74. bool gmac;
  75. bool gmac4;
  76. bool xgmac;
  77. u32 min_id;
  78. u32 dev_id;
  79. const struct stmmac_regs_off regs;
  80. const void *desc;
  81. const void *dma;
  82. const void *mac;
  83. const void *hwtimestamp;
  84. const void *mode;
  85. const void *tc;
  86. const void *mmc;
  87. int (*setup)(struct stmmac_priv *priv);
  88. int (*quirks)(struct stmmac_priv *priv);
  89. } stmmac_hw[] = {
  90. /* NOTE: New HW versions shall go to the end of this table */
  91. {
  92. .gmac = false,
  93. .gmac4 = false,
  94. .xgmac = false,
  95. .min_id = 0,
  96. .regs = {
  97. .ptp_off = PTP_GMAC3_X_OFFSET,
  98. .mmc_off = MMC_GMAC3_X_OFFSET,
  99. },
  100. .desc = NULL,
  101. .dma = &dwmac100_dma_ops,
  102. .mac = &dwmac100_ops,
  103. .hwtimestamp = &stmmac_ptp,
  104. .mode = NULL,
  105. .tc = NULL,
  106. .mmc = &dwmac_mmc_ops,
  107. .setup = dwmac100_setup,
  108. .quirks = stmmac_dwmac1_quirks,
  109. }, {
  110. .gmac = true,
  111. .gmac4 = false,
  112. .xgmac = false,
  113. .min_id = 0,
  114. .regs = {
  115. .ptp_off = PTP_GMAC3_X_OFFSET,
  116. .mmc_off = MMC_GMAC3_X_OFFSET,
  117. },
  118. .desc = NULL,
  119. .dma = &dwmac1000_dma_ops,
  120. .mac = &dwmac1000_ops,
  121. .hwtimestamp = &stmmac_ptp,
  122. .mode = NULL,
  123. .tc = NULL,
  124. .mmc = &dwmac_mmc_ops,
  125. .setup = dwmac1000_setup,
  126. .quirks = stmmac_dwmac1_quirks,
  127. }, {
  128. .gmac = false,
  129. .gmac4 = true,
  130. .xgmac = false,
  131. .min_id = 0,
  132. .regs = {
  133. .ptp_off = PTP_GMAC4_OFFSET,
  134. .mmc_off = MMC_GMAC4_OFFSET,
  135. },
  136. .desc = &dwmac4_desc_ops,
  137. .dma = &dwmac4_dma_ops,
  138. .mac = &dwmac4_ops,
  139. .hwtimestamp = &stmmac_ptp,
  140. .mode = NULL,
  141. .tc = &dwmac510_tc_ops,
  142. .mmc = &dwmac_mmc_ops,
  143. .setup = dwmac4_setup,
  144. .quirks = stmmac_dwmac4_quirks,
  145. }, {
  146. .gmac = false,
  147. .gmac4 = true,
  148. .xgmac = false,
  149. .min_id = DWMAC_CORE_4_00,
  150. .regs = {
  151. .ptp_off = PTP_GMAC4_OFFSET,
  152. .mmc_off = MMC_GMAC4_OFFSET,
  153. },
  154. .desc = &dwmac4_desc_ops,
  155. .dma = &dwmac4_dma_ops,
  156. .mac = &dwmac410_ops,
  157. .hwtimestamp = &stmmac_ptp,
  158. .mode = &dwmac4_ring_mode_ops,
  159. .tc = &dwmac510_tc_ops,
  160. .mmc = &dwmac_mmc_ops,
  161. .setup = dwmac4_setup,
  162. .quirks = NULL,
  163. }, {
  164. .gmac = false,
  165. .gmac4 = true,
  166. .xgmac = false,
  167. .min_id = DWMAC_CORE_4_10,
  168. .regs = {
  169. .ptp_off = PTP_GMAC4_OFFSET,
  170. .mmc_off = MMC_GMAC4_OFFSET,
  171. },
  172. .desc = &dwmac4_desc_ops,
  173. .dma = &dwmac410_dma_ops,
  174. .mac = &dwmac410_ops,
  175. .hwtimestamp = &stmmac_ptp,
  176. .mode = &dwmac4_ring_mode_ops,
  177. .tc = &dwmac510_tc_ops,
  178. .mmc = &dwmac_mmc_ops,
  179. .setup = dwmac4_setup,
  180. .quirks = NULL,
  181. }, {
  182. .gmac = false,
  183. .gmac4 = true,
  184. .xgmac = false,
  185. .min_id = DWMAC_CORE_5_10,
  186. .regs = {
  187. .ptp_off = PTP_GMAC4_OFFSET,
  188. .mmc_off = MMC_GMAC4_OFFSET,
  189. },
  190. .desc = &dwmac4_desc_ops,
  191. .dma = &dwmac410_dma_ops,
  192. .mac = &dwmac510_ops,
  193. .hwtimestamp = &stmmac_ptp,
  194. .mode = &dwmac4_ring_mode_ops,
  195. .tc = &dwmac510_tc_ops,
  196. .mmc = &dwmac_mmc_ops,
  197. .setup = dwmac4_setup,
  198. .quirks = NULL,
  199. }, {
  200. .gmac = false,
  201. .gmac4 = false,
  202. .xgmac = true,
  203. .min_id = DWXGMAC_CORE_2_10,
  204. .dev_id = DWXGMAC_ID,
  205. .regs = {
  206. .ptp_off = PTP_XGMAC_OFFSET,
  207. .mmc_off = MMC_XGMAC_OFFSET,
  208. },
  209. .desc = &dwxgmac210_desc_ops,
  210. .dma = &dwxgmac210_dma_ops,
  211. .mac = &dwxgmac210_ops,
  212. .hwtimestamp = &stmmac_ptp,
  213. .mode = NULL,
  214. .tc = &dwmac510_tc_ops,
  215. .mmc = &dwxgmac_mmc_ops,
  216. .setup = dwxgmac2_setup,
  217. .quirks = NULL,
  218. }, {
  219. .gmac = false,
  220. .gmac4 = false,
  221. .xgmac = true,
  222. .min_id = DWXLGMAC_CORE_2_00,
  223. .dev_id = DWXLGMAC_ID,
  224. .regs = {
  225. .ptp_off = PTP_XGMAC_OFFSET,
  226. .mmc_off = MMC_XGMAC_OFFSET,
  227. },
  228. .desc = &dwxgmac210_desc_ops,
  229. .dma = &dwxgmac210_dma_ops,
  230. .mac = &dwxlgmac2_ops,
  231. .hwtimestamp = &stmmac_ptp,
  232. .mode = NULL,
  233. .tc = &dwmac510_tc_ops,
  234. .mmc = &dwxgmac_mmc_ops,
  235. .setup = dwxlgmac2_setup,
  236. .quirks = stmmac_dwxlgmac_quirks,
  237. },
  238. };
  239. int stmmac_hwif_init(struct stmmac_priv *priv)
  240. {
  241. bool needs_xgmac = priv->plat->has_xgmac;
  242. bool needs_gmac4 = priv->plat->has_gmac4;
  243. bool needs_gmac = priv->plat->has_gmac;
  244. const struct stmmac_hwif_entry *entry;
  245. struct mac_device_info *mac;
  246. bool needs_setup = true;
  247. u32 id, dev_id = 0;
  248. int i, ret;
  249. if (needs_gmac) {
  250. id = stmmac_get_id(priv, GMAC_VERSION);
  251. } else if (needs_gmac4 || needs_xgmac) {
  252. id = stmmac_get_id(priv, GMAC4_VERSION);
  253. if (needs_xgmac)
  254. dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION);
  255. } else {
  256. id = 0;
  257. }
  258. /* Save ID for later use */
  259. priv->synopsys_id = id;
  260. /* Lets assume some safe values first */
  261. priv->ptpaddr = priv->ioaddr +
  262. (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
  263. priv->mmcaddr = priv->ioaddr +
  264. (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
  265. /* Check for HW specific setup first */
  266. if (priv->plat->setup) {
  267. mac = priv->plat->setup(priv);
  268. needs_setup = false;
  269. } else {
  270. mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
  271. }
  272. if (!mac)
  273. return -ENOMEM;
  274. /* Fallback to generic HW */
  275. for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) {
  276. entry = &stmmac_hw[i];
  277. if (needs_gmac ^ entry->gmac)
  278. continue;
  279. if (needs_gmac4 ^ entry->gmac4)
  280. continue;
  281. if (needs_xgmac ^ entry->xgmac)
  282. continue;
  283. /* Use synopsys_id var because some setups can override this */
  284. if (priv->synopsys_id < entry->min_id)
  285. continue;
  286. if (needs_xgmac && (dev_id ^ entry->dev_id))
  287. continue;
  288. /* Only use generic HW helpers if needed */
  289. mac->desc = mac->desc ? : entry->desc;
  290. mac->dma = mac->dma ? : entry->dma;
  291. mac->mac = mac->mac ? : entry->mac;
  292. mac->ptp = mac->ptp ? : entry->hwtimestamp;
  293. mac->mode = mac->mode ? : entry->mode;
  294. mac->tc = mac->tc ? : entry->tc;
  295. mac->mmc = mac->mmc ? : entry->mmc;
  296. priv->hw = mac;
  297. priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
  298. priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
  299. /* Entry found */
  300. if (needs_setup) {
  301. ret = entry->setup(priv);
  302. if (ret)
  303. return ret;
  304. }
  305. /* Save quirks, if needed for posterior use */
  306. priv->hwif_quirks = entry->quirks;
  307. return 0;
  308. }
  309. dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n",
  310. id, needs_gmac, needs_gmac4);
  311. return -EINVAL;
  312. }