dwmac5.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. // Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
  3. // stmmac Support for 5.xx Ethernet QoS cores
  4. #include <linux/bitops.h>
  5. #include <linux/iopoll.h>
  6. #include "common.h"
  7. #include "dwmac4.h"
  8. #include "dwmac5.h"
  9. #include "stmmac.h"
  10. #include "stmmac_ptp.h"
  11. struct dwmac5_error_desc {
  12. bool valid;
  13. const char *desc;
  14. const char *detailed_desc;
  15. };
  16. #define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field)
  17. static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
  18. const char *module_name, const struct dwmac5_error_desc *desc,
  19. unsigned long field_offset, struct stmmac_safety_stats *stats)
  20. {
  21. unsigned long loc, mask;
  22. u8 *bptr = (u8 *)stats;
  23. unsigned long *ptr;
  24. ptr = (unsigned long *)(bptr + field_offset);
  25. mask = value;
  26. for_each_set_bit(loc, &mask, 32) {
  27. netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
  28. "correctable" : "uncorrectable", module_name,
  29. desc[loc].desc, desc[loc].detailed_desc);
  30. /* Update counters */
  31. ptr[loc]++;
  32. }
  33. }
  34. static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
  35. { true, "ATPES", "Application Transmit Interface Parity Check Error" },
  36. { true, "TPES", "TSO Data Path Parity Check Error" },
  37. { true, "RDPES", "Read Descriptor Parity Check Error" },
  38. { true, "MPES", "MTL Data Path Parity Check Error" },
  39. { true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
  40. { true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
  41. { true, "CWPES", "CSR Write Data Path Parity Check Error" },
  42. { true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
  43. { true, "TTES", "TX FSM Timeout Error" },
  44. { true, "RTES", "RX FSM Timeout Error" },
  45. { true, "CTES", "CSR FSM Timeout Error" },
  46. { true, "ATES", "APP FSM Timeout Error" },
  47. { true, "PTES", "PTP FSM Timeout Error" },
  48. { true, "T125ES", "TX125 FSM Timeout Error" },
  49. { true, "R125ES", "RX125 FSM Timeout Error" },
  50. { true, "RVCTES", "REV MDC FSM Timeout Error" },
  51. { true, "MSTTES", "Master Read/Write Timeout Error" },
  52. { true, "SLVTES", "Slave Read/Write Timeout Error" },
  53. { true, "ATITES", "Application Timeout on ATI Interface Error" },
  54. { true, "ARITES", "Application Timeout on ARI Interface Error" },
  55. { false, "UNKNOWN", "Unknown Error" }, /* 20 */
  56. { false, "UNKNOWN", "Unknown Error" }, /* 21 */
  57. { false, "UNKNOWN", "Unknown Error" }, /* 22 */
  58. { false, "UNKNOWN", "Unknown Error" }, /* 23 */
  59. { true, "FSMPES", "FSM State Parity Error" },
  60. { false, "UNKNOWN", "Unknown Error" }, /* 25 */
  61. { false, "UNKNOWN", "Unknown Error" }, /* 26 */
  62. { false, "UNKNOWN", "Unknown Error" }, /* 27 */
  63. { false, "UNKNOWN", "Unknown Error" }, /* 28 */
  64. { false, "UNKNOWN", "Unknown Error" }, /* 29 */
  65. { false, "UNKNOWN", "Unknown Error" }, /* 30 */
  66. { false, "UNKNOWN", "Unknown Error" }, /* 31 */
  67. };
  68. static void dwmac5_handle_mac_err(struct net_device *ndev,
  69. void __iomem *ioaddr, bool correctable,
  70. struct stmmac_safety_stats *stats)
  71. {
  72. u32 value;
  73. value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
  74. writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
  75. dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
  76. STAT_OFF(mac_errors), stats);
  77. }
  78. static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
  79. { true, "TXCES", "MTL TX Memory Error" },
  80. { true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
  81. { true, "TXUES", "MTL TX Memory Error" },
  82. { false, "UNKNOWN", "Unknown Error" }, /* 3 */
  83. { true, "RXCES", "MTL RX Memory Error" },
  84. { true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
  85. { true, "RXUES", "MTL RX Memory Error" },
  86. { false, "UNKNOWN", "Unknown Error" }, /* 7 */
  87. { true, "ECES", "MTL EST Memory Error" },
  88. { true, "EAMS", "MTL EST Memory Address Mismatch Error" },
  89. { true, "EUES", "MTL EST Memory Error" },
  90. { false, "UNKNOWN", "Unknown Error" }, /* 11 */
  91. { true, "RPCES", "MTL RX Parser Memory Error" },
  92. { true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
  93. { true, "RPUES", "MTL RX Parser Memory Error" },
  94. { false, "UNKNOWN", "Unknown Error" }, /* 15 */
  95. { false, "UNKNOWN", "Unknown Error" }, /* 16 */
  96. { false, "UNKNOWN", "Unknown Error" }, /* 17 */
  97. { false, "UNKNOWN", "Unknown Error" }, /* 18 */
  98. { false, "UNKNOWN", "Unknown Error" }, /* 19 */
  99. { false, "UNKNOWN", "Unknown Error" }, /* 20 */
  100. { false, "UNKNOWN", "Unknown Error" }, /* 21 */
  101. { false, "UNKNOWN", "Unknown Error" }, /* 22 */
  102. { false, "UNKNOWN", "Unknown Error" }, /* 23 */
  103. { false, "UNKNOWN", "Unknown Error" }, /* 24 */
  104. { false, "UNKNOWN", "Unknown Error" }, /* 25 */
  105. { false, "UNKNOWN", "Unknown Error" }, /* 26 */
  106. { false, "UNKNOWN", "Unknown Error" }, /* 27 */
  107. { false, "UNKNOWN", "Unknown Error" }, /* 28 */
  108. { false, "UNKNOWN", "Unknown Error" }, /* 29 */
  109. { false, "UNKNOWN", "Unknown Error" }, /* 30 */
  110. { false, "UNKNOWN", "Unknown Error" }, /* 31 */
  111. };
  112. static void dwmac5_handle_mtl_err(struct net_device *ndev,
  113. void __iomem *ioaddr, bool correctable,
  114. struct stmmac_safety_stats *stats)
  115. {
  116. u32 value;
  117. value = readl(ioaddr + MTL_ECC_INT_STATUS);
  118. writel(value, ioaddr + MTL_ECC_INT_STATUS);
  119. dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
  120. STAT_OFF(mtl_errors), stats);
  121. }
  122. static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
  123. { true, "TCES", "DMA TSO Memory Error" },
  124. { true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
  125. { true, "TUES", "DMA TSO Memory Error" },
  126. { false, "UNKNOWN", "Unknown Error" }, /* 3 */
  127. { false, "UNKNOWN", "Unknown Error" }, /* 4 */
  128. { false, "UNKNOWN", "Unknown Error" }, /* 5 */
  129. { false, "UNKNOWN", "Unknown Error" }, /* 6 */
  130. { false, "UNKNOWN", "Unknown Error" }, /* 7 */
  131. { false, "UNKNOWN", "Unknown Error" }, /* 8 */
  132. { false, "UNKNOWN", "Unknown Error" }, /* 9 */
  133. { false, "UNKNOWN", "Unknown Error" }, /* 10 */
  134. { false, "UNKNOWN", "Unknown Error" }, /* 11 */
  135. { false, "UNKNOWN", "Unknown Error" }, /* 12 */
  136. { false, "UNKNOWN", "Unknown Error" }, /* 13 */
  137. { false, "UNKNOWN", "Unknown Error" }, /* 14 */
  138. { false, "UNKNOWN", "Unknown Error" }, /* 15 */
  139. { false, "UNKNOWN", "Unknown Error" }, /* 16 */
  140. { false, "UNKNOWN", "Unknown Error" }, /* 17 */
  141. { false, "UNKNOWN", "Unknown Error" }, /* 18 */
  142. { false, "UNKNOWN", "Unknown Error" }, /* 19 */
  143. { false, "UNKNOWN", "Unknown Error" }, /* 20 */
  144. { false, "UNKNOWN", "Unknown Error" }, /* 21 */
  145. { false, "UNKNOWN", "Unknown Error" }, /* 22 */
  146. { false, "UNKNOWN", "Unknown Error" }, /* 23 */
  147. { false, "UNKNOWN", "Unknown Error" }, /* 24 */
  148. { false, "UNKNOWN", "Unknown Error" }, /* 25 */
  149. { false, "UNKNOWN", "Unknown Error" }, /* 26 */
  150. { false, "UNKNOWN", "Unknown Error" }, /* 27 */
  151. { false, "UNKNOWN", "Unknown Error" }, /* 28 */
  152. { false, "UNKNOWN", "Unknown Error" }, /* 29 */
  153. { false, "UNKNOWN", "Unknown Error" }, /* 30 */
  154. { false, "UNKNOWN", "Unknown Error" }, /* 31 */
  155. };
  156. static void dwmac5_handle_dma_err(struct net_device *ndev,
  157. void __iomem *ioaddr, bool correctable,
  158. struct stmmac_safety_stats *stats)
  159. {
  160. u32 value;
  161. value = readl(ioaddr + DMA_ECC_INT_STATUS);
  162. writel(value, ioaddr + DMA_ECC_INT_STATUS);
  163. dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
  164. STAT_OFF(dma_errors), stats);
  165. }
  166. int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
  167. struct stmmac_safety_feature_cfg *safety_feat_cfg)
  168. {
  169. struct stmmac_safety_feature_cfg all_safety_feats = {
  170. .tsoee = 1,
  171. .mrxpee = 1,
  172. .mestee = 1,
  173. .mrxee = 1,
  174. .mtxee = 1,
  175. .epsi = 1,
  176. .edpp = 1,
  177. .prtyen = 1,
  178. .tmouten = 1,
  179. };
  180. u32 value;
  181. if (!asp)
  182. return -EINVAL;
  183. if (!safety_feat_cfg)
  184. safety_feat_cfg = &all_safety_feats;
  185. /* 1. Enable Safety Features */
  186. value = readl(ioaddr + MTL_ECC_CONTROL);
  187. value |= MEEAO; /* MTL ECC Error Addr Status Override */
  188. if (safety_feat_cfg->tsoee)
  189. value |= TSOEE; /* TSO ECC */
  190. if (safety_feat_cfg->mrxpee)
  191. value |= MRXPEE; /* MTL RX Parser ECC */
  192. if (safety_feat_cfg->mestee)
  193. value |= MESTEE; /* MTL EST ECC */
  194. if (safety_feat_cfg->mrxee)
  195. value |= MRXEE; /* MTL RX FIFO ECC */
  196. if (safety_feat_cfg->mtxee)
  197. value |= MTXEE; /* MTL TX FIFO ECC */
  198. writel(value, ioaddr + MTL_ECC_CONTROL);
  199. /* 2. Enable MTL Safety Interrupts */
  200. value = readl(ioaddr + MTL_ECC_INT_ENABLE);
  201. value |= RPCEIE; /* RX Parser Memory Correctable Error */
  202. value |= ECEIE; /* EST Memory Correctable Error */
  203. value |= RXCEIE; /* RX Memory Correctable Error */
  204. value |= TXCEIE; /* TX Memory Correctable Error */
  205. writel(value, ioaddr + MTL_ECC_INT_ENABLE);
  206. /* 3. Enable DMA Safety Interrupts */
  207. value = readl(ioaddr + DMA_ECC_INT_ENABLE);
  208. value |= TCEIE; /* TSO Memory Correctable Error */
  209. writel(value, ioaddr + DMA_ECC_INT_ENABLE);
  210. /* Only ECC Protection for External Memory feature is selected */
  211. if (asp <= 0x1)
  212. return 0;
  213. /* 5. Enable Parity and Timeout for FSM */
  214. value = readl(ioaddr + MAC_FSM_CONTROL);
  215. if (safety_feat_cfg->prtyen)
  216. value |= PRTYEN; /* FSM Parity Feature */
  217. if (safety_feat_cfg->tmouten)
  218. value |= TMOUTEN; /* FSM Timeout Feature */
  219. writel(value, ioaddr + MAC_FSM_CONTROL);
  220. /* 4. Enable Data Parity Protection */
  221. value = readl(ioaddr + MTL_DPP_CONTROL);
  222. if (safety_feat_cfg->edpp)
  223. value |= EDPP;
  224. writel(value, ioaddr + MTL_DPP_CONTROL);
  225. /*
  226. * All the Automotive Safety features are selected without the "Parity
  227. * Port Enable for external interface" feature.
  228. */
  229. if (asp <= 0x2)
  230. return 0;
  231. if (safety_feat_cfg->epsi)
  232. value |= EPSI;
  233. writel(value, ioaddr + MTL_DPP_CONTROL);
  234. return 0;
  235. }
  236. int dwmac5_safety_feat_irq_status(struct net_device *ndev,
  237. void __iomem *ioaddr, unsigned int asp,
  238. struct stmmac_safety_stats *stats)
  239. {
  240. bool err, corr;
  241. u32 mtl, dma;
  242. int ret = 0;
  243. if (!asp)
  244. return -EINVAL;
  245. mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
  246. dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
  247. err = (mtl & MCSIS) || (dma & MCSIS);
  248. corr = false;
  249. if (err) {
  250. dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);
  251. ret |= !corr;
  252. }
  253. err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
  254. corr = (mtl & MECIS) || (dma & MSCIS);
  255. if (err) {
  256. dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
  257. ret |= !corr;
  258. }
  259. err = dma & (DEUIS | DECIS);
  260. corr = dma & DECIS;
  261. if (err) {
  262. dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
  263. ret |= !corr;
  264. }
  265. return ret;
  266. }
  267. static const struct dwmac5_error {
  268. const struct dwmac5_error_desc *desc;
  269. } dwmac5_all_errors[] = {
  270. { dwmac5_mac_errors },
  271. { dwmac5_mtl_errors },
  272. { dwmac5_dma_errors },
  273. };
  274. int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
  275. int index, unsigned long *count, const char **desc)
  276. {
  277. int module = index / 32, offset = index % 32;
  278. unsigned long *ptr = (unsigned long *)stats;
  279. if (module >= ARRAY_SIZE(dwmac5_all_errors))
  280. return -EINVAL;
  281. if (!dwmac5_all_errors[module].desc[offset].valid)
  282. return -EINVAL;
  283. if (count)
  284. *count = *(ptr + index);
  285. if (desc)
  286. *desc = dwmac5_all_errors[module].desc[offset].desc;
  287. return 0;
  288. }
  289. static int dwmac5_rxp_disable(void __iomem *ioaddr)
  290. {
  291. u32 val;
  292. val = readl(ioaddr + MTL_OPERATION_MODE);
  293. val &= ~MTL_FRPE;
  294. writel(val, ioaddr + MTL_OPERATION_MODE);
  295. return readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
  296. val & RXPI, 1, 10000);
  297. }
  298. static void dwmac5_rxp_enable(void __iomem *ioaddr)
  299. {
  300. u32 val;
  301. val = readl(ioaddr + MTL_OPERATION_MODE);
  302. val |= MTL_FRPE;
  303. writel(val, ioaddr + MTL_OPERATION_MODE);
  304. }
  305. static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
  306. struct stmmac_tc_entry *entry,
  307. int pos)
  308. {
  309. int ret, i;
  310. for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
  311. int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
  312. u32 val;
  313. /* Wait for ready */
  314. ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
  315. val, !(val & STARTBUSY), 1, 10000);
  316. if (ret)
  317. return ret;
  318. /* Write data */
  319. val = *((u32 *)&entry->val + i);
  320. writel(val, ioaddr + MTL_RXP_IACC_DATA);
  321. /* Write pos */
  322. val = real_pos & ADDR;
  323. writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
  324. /* Write OP */
  325. val |= WRRDN;
  326. writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
  327. /* Start Write */
  328. val |= STARTBUSY;
  329. writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
  330. /* Wait for done */
  331. ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
  332. val, !(val & STARTBUSY), 1, 10000);
  333. if (ret)
  334. return ret;
  335. }
  336. return 0;
  337. }
  338. static struct stmmac_tc_entry *
  339. dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
  340. u32 curr_prio)
  341. {
  342. struct stmmac_tc_entry *entry;
  343. u32 min_prio = ~0x0;
  344. int i, min_prio_idx;
  345. bool found = false;
  346. for (i = count - 1; i >= 0; i--) {
  347. entry = &entries[i];
  348. /* Do not update unused entries */
  349. if (!entry->in_use)
  350. continue;
  351. /* Do not update already updated entries (i.e. fragments) */
  352. if (entry->in_hw)
  353. continue;
  354. /* Let last entry be updated last */
  355. if (entry->is_last)
  356. continue;
  357. /* Do not return fragments */
  358. if (entry->is_frag)
  359. continue;
  360. /* Check if we already checked this prio */
  361. if (entry->prio < curr_prio)
  362. continue;
  363. /* Check if this is the minimum prio */
  364. if (entry->prio < min_prio) {
  365. min_prio = entry->prio;
  366. min_prio_idx = i;
  367. found = true;
  368. }
  369. }
  370. if (found)
  371. return &entries[min_prio_idx];
  372. return NULL;
  373. }
  374. int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
  375. unsigned int count)
  376. {
  377. struct stmmac_tc_entry *entry, *frag;
  378. int i, ret, nve = 0;
  379. u32 curr_prio = 0;
  380. u32 old_val, val;
  381. /* Force disable RX */
  382. old_val = readl(ioaddr + GMAC_CONFIG);
  383. val = old_val & ~GMAC_CONFIG_RE;
  384. writel(val, ioaddr + GMAC_CONFIG);
  385. /* Disable RX Parser */
  386. ret = dwmac5_rxp_disable(ioaddr);
  387. if (ret)
  388. goto re_enable;
  389. /* Set all entries as NOT in HW */
  390. for (i = 0; i < count; i++) {
  391. entry = &entries[i];
  392. entry->in_hw = false;
  393. }
  394. /* Update entries by reverse order */
  395. while (1) {
  396. entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
  397. if (!entry)
  398. break;
  399. curr_prio = entry->prio;
  400. frag = entry->frag_ptr;
  401. /* Set special fragment requirements */
  402. if (frag) {
  403. entry->val.af = 0;
  404. entry->val.rf = 0;
  405. entry->val.nc = 1;
  406. entry->val.ok_index = nve + 2;
  407. }
  408. ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
  409. if (ret)
  410. goto re_enable;
  411. entry->table_pos = nve++;
  412. entry->in_hw = true;
  413. if (frag && !frag->in_hw) {
  414. ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
  415. if (ret)
  416. goto re_enable;
  417. frag->table_pos = nve++;
  418. frag->in_hw = true;
  419. }
  420. }
  421. if (!nve)
  422. goto re_enable;
  423. /* Update all pass entry */
  424. for (i = 0; i < count; i++) {
  425. entry = &entries[i];
  426. if (!entry->is_last)
  427. continue;
  428. ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
  429. if (ret)
  430. goto re_enable;
  431. entry->table_pos = nve++;
  432. }
  433. /* Assume n. of parsable entries == n. of valid entries */
  434. val = (nve << 16) & NPE;
  435. val |= nve & NVE;
  436. writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
  437. /* Enable RX Parser */
  438. dwmac5_rxp_enable(ioaddr);
  439. re_enable:
  440. /* Re-enable RX */
  441. writel(old_val, ioaddr + GMAC_CONFIG);
  442. return ret;
  443. }
  444. int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
  445. struct stmmac_pps_cfg *cfg, bool enable,
  446. u32 sub_second_inc, u32 systime_flags)
  447. {
  448. u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
  449. u32 val = readl(ioaddr + MAC_PPS_CONTROL);
  450. u64 period;
  451. if (!cfg->available)
  452. return -EINVAL;
  453. if (tnsec & TRGTBUSY0)
  454. return -EBUSY;
  455. if (!sub_second_inc || !systime_flags)
  456. return -EINVAL;
  457. val &= ~PPSx_MASK(index);
  458. if (!enable) {
  459. val |= PPSCMDx(index, 0x5);
  460. val |= PPSEN0;
  461. writel(val, ioaddr + MAC_PPS_CONTROL);
  462. return 0;
  463. }
  464. val |= TRGTMODSELx(index, 0x2);
  465. val |= PPSEN0;
  466. writel(val, ioaddr + MAC_PPS_CONTROL);
  467. writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
  468. if (!(systime_flags & PTP_TCR_TSCTRLSSR))
  469. cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
  470. writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
  471. period = cfg->period.tv_sec * 1000000000;
  472. period += cfg->period.tv_nsec;
  473. do_div(period, sub_second_inc);
  474. if (period <= 1)
  475. return -EINVAL;
  476. writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
  477. period >>= 1;
  478. if (period <= 1)
  479. return -EINVAL;
  480. writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
  481. /* Finally, activate it */
  482. val |= PPSCMDx(index, 0x2);
  483. writel(val, ioaddr + MAC_PPS_CONTROL);
  484. return 0;
  485. }
  486. static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
  487. {
  488. u32 ctrl;
  489. writel(val, ioaddr + MTL_EST_GCL_DATA);
  490. ctrl = (reg << ADDR_SHIFT);
  491. ctrl |= gcl ? 0 : GCRR;
  492. writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
  493. ctrl |= SRWO;
  494. writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
  495. return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
  496. ctrl, !(ctrl & SRWO), 100, 5000);
  497. }
  498. int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
  499. unsigned int ptp_rate)
  500. {
  501. int i, ret = 0x0;
  502. u32 ctrl;
  503. ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
  504. ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
  505. ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
  506. ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
  507. ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
  508. ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
  509. if (ret)
  510. return ret;
  511. for (i = 0; i < cfg->gcl_size; i++) {
  512. ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
  513. if (ret)
  514. return ret;
  515. }
  516. ctrl = readl(ioaddr + MTL_EST_CONTROL);
  517. ctrl &= ~PTOV;
  518. ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
  519. if (cfg->enable)
  520. ctrl |= EEST | SSWL;
  521. else
  522. ctrl &= ~EEST;
  523. writel(ctrl, ioaddr + MTL_EST_CONTROL);
  524. /* Configure EST interrupt */
  525. if (cfg->enable)
  526. ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
  527. else
  528. ctrl = 0;
  529. writel(ctrl, ioaddr + MTL_EST_INT_EN);
  530. return 0;
  531. }
  532. void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
  533. struct stmmac_extra_stats *x, u32 txqcnt)
  534. {
  535. u32 status, value, feqn, hbfq, hbfs, btrl;
  536. u32 txqcnt_mask = (1 << txqcnt) - 1;
  537. status = readl(ioaddr + MTL_EST_STATUS);
  538. value = (CGCE | HLBS | HLBF | BTRE | SWLC);
  539. /* Return if there is no error */
  540. if (!(status & value))
  541. return;
  542. if (status & CGCE) {
  543. /* Clear Interrupt */
  544. writel(CGCE, ioaddr + MTL_EST_STATUS);
  545. x->mtl_est_cgce++;
  546. }
  547. if (status & HLBS) {
  548. value = readl(ioaddr + MTL_EST_SCH_ERR);
  549. value &= txqcnt_mask;
  550. x->mtl_est_hlbs++;
  551. /* Clear Interrupt */
  552. writel(value, ioaddr + MTL_EST_SCH_ERR);
  553. /* Collecting info to shows all the queues that has HLBS
  554. * issue. The only way to clear this is to clear the
  555. * statistic
  556. */
  557. if (net_ratelimit())
  558. netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
  559. }
  560. if (status & HLBF) {
  561. value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
  562. feqn = value & txqcnt_mask;
  563. value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
  564. hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
  565. hbfs = value & SZ_CAP_HBFS_MASK;
  566. x->mtl_est_hlbf++;
  567. /* Clear Interrupt */
  568. writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
  569. if (net_ratelimit())
  570. netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
  571. hbfq, hbfs);
  572. }
  573. if (status & BTRE) {
  574. if ((status & BTRL) == BTRL_MAX)
  575. x->mtl_est_btrlm++;
  576. else
  577. x->mtl_est_btre++;
  578. btrl = (status & BTRL) >> BTRL_SHIFT;
  579. if (net_ratelimit())
  580. netdev_info(dev, "EST: BTR Error Loop Count %u\n",
  581. btrl);
  582. writel(BTRE, ioaddr + MTL_EST_STATUS);
  583. }
  584. if (status & SWLC) {
  585. writel(SWLC, ioaddr + MTL_EST_STATUS);
  586. netdev_info(dev, "EST: SWOL has been switched\n");
  587. }
  588. }
  589. void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
  590. u32 num_txq, u32 num_rxq,
  591. bool enable)
  592. {
  593. u32 value;
  594. if (enable) {
  595. cfg->fpe_csr = EFPE;
  596. value = readl(ioaddr + GMAC_RXQ_CTRL1);
  597. value &= ~GMAC_RXQCTRL_FPRQ;
  598. value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
  599. writel(value, ioaddr + GMAC_RXQ_CTRL1);
  600. } else {
  601. cfg->fpe_csr = 0;
  602. }
  603. writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
  604. }
  605. int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
  606. {
  607. u32 value;
  608. int status;
  609. status = FPE_EVENT_UNKNOWN;
  610. /* Reads from the MAC_FPE_CTRL_STS register should only be performed
  611. * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read"
  612. */
  613. value = readl(ioaddr + MAC_FPE_CTRL_STS);
  614. if (value & TRSP) {
  615. status |= FPE_EVENT_TRSP;
  616. netdev_info(dev, "FPE: Respond mPacket is transmitted\n");
  617. }
  618. if (value & TVER) {
  619. status |= FPE_EVENT_TVER;
  620. netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
  621. }
  622. if (value & RRSP) {
  623. status |= FPE_EVENT_RRSP;
  624. netdev_info(dev, "FPE: Respond mPacket is received\n");
  625. }
  626. if (value & RVER) {
  627. status |= FPE_EVENT_RVER;
  628. netdev_info(dev, "FPE: Verify mPacket is received\n");
  629. }
  630. return status;
  631. }
  632. void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
  633. enum stmmac_mpacket_type type)
  634. {
  635. u32 value = cfg->fpe_csr;
  636. if (type == MPACKET_VERIFY)
  637. value |= SVER;
  638. else if (type == MPACKET_RESPONSE)
  639. value |= SRSP;
  640. writel(value, ioaddr + MAC_FPE_CTRL_STS);
  641. }