xilinx_emac.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /******************************************************************************
  2. *
  3. * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
  4. * AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
  5. * SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
  6. * OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
  7. * APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
  8. * THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
  9. * AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
  10. * FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
  11. * WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
  12. * IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
  13. * REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
  14. * INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  15. * FOR A PARTICULAR PURPOSE.
  16. *
  17. * (C) Copyright 2007-2008 Michal Simek
  18. * Michal SIMEK <monstr@monstr.eu>
  19. *
  20. * (c) Copyright 2003 Xilinx Inc.
  21. * All rights reserved.
  22. *
  23. ******************************************************************************/
  24. #include <config.h>
  25. #include <common.h>
  26. #include <net.h>
  27. #include <asm/io.h>
  28. #include <asm/asm.h>
  29. #undef DEBUG
  30. typedef struct {
  31. u32 regbaseaddress; /* Base address of registers */
  32. u32 databaseaddress; /* Base address of data for FIFOs */
  33. } xpacketfifov100b;
  34. typedef struct {
  35. u32 baseaddress; /* Base address (of IPIF) */
  36. u32 isstarted; /* Device is currently started 0-no, 1-yes */
  37. xpacketfifov100b recvfifo; /* FIFO used to receive frames */
  38. xpacketfifov100b sendfifo; /* FIFO used to send frames */
  39. } xemac;
  40. #define XIIF_V123B_IISR_OFFSET 32UL /* IP interrupt status register */
  41. #define XIIF_V123B_RESET_MASK 0xAUL
  42. #define XIIF_V123B_RESETR_OFFSET 64UL /* reset register */
  43. /* This constant is used with the Reset Register */
  44. #define XPF_RESET_FIFO_MASK 0x0000000A
  45. #define XPF_COUNT_STATUS_REG_OFFSET 4UL
  46. /* These constants are used with the Occupancy/Vacancy Count Register. This
  47. * register also contains FIFO status */
  48. #define XPF_COUNT_MASK 0x0000FFFF
  49. #define XPF_DEADLOCK_MASK 0x20000000
  50. /* Offset of the MAC registers from the IPIF base address */
  51. #define XEM_REG_OFFSET 0x1100UL
  52. /*
  53. * Register offsets for the Ethernet MAC. Each register is 32 bits.
  54. */
  55. #define XEM_ECR_OFFSET (XEM_REG_OFFSET + 0x4) /* MAC Control */
  56. #define XEM_SAH_OFFSET (XEM_REG_OFFSET + 0xC) /* Station addr, high */
  57. #define XEM_SAL_OFFSET (XEM_REG_OFFSET + 0x10) /* Station addr, low */
  58. #define XEM_RPLR_OFFSET (XEM_REG_OFFSET + 0x1C) /* Rx packet length */
  59. #define XEM_TPLR_OFFSET (XEM_REG_OFFSET + 0x20) /* Tx packet length */
  60. #define XEM_TSR_OFFSET (XEM_REG_OFFSET + 0x24) /* Tx status */
  61. #define XEM_PFIFO_OFFSET 0x2000UL
  62. /* Tx registers */
  63. #define XEM_PFIFO_TXREG_OFFSET (XEM_PFIFO_OFFSET + 0x0)
  64. /* Rx registers */
  65. #define XEM_PFIFO_RXREG_OFFSET (XEM_PFIFO_OFFSET + 0x10)
  66. /* Tx keyhole */
  67. #define XEM_PFIFO_TXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x100)
  68. /* Rx keyhole */
  69. #define XEM_PFIFO_RXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x200)
  70. /*
  71. * EMAC Interrupt Registers (Status and Enable) masks. These registers are
  72. * part of the IPIF IP Interrupt registers
  73. */
  74. /* A mask for all transmit interrupts, used in polled mode */
  75. #define XEM_EIR_XMIT_ALL_MASK (XEM_EIR_XMIT_DONE_MASK |\
  76. XEM_EIR_XMIT_ERROR_MASK | \
  77. XEM_EIR_XMIT_SFIFO_EMPTY_MASK |\
  78. XEM_EIR_XMIT_LFIFO_FULL_MASK)
  79. /* Xmit complete */
  80. #define XEM_EIR_XMIT_DONE_MASK 0x00000001UL
  81. /* Recv complete */
  82. #define XEM_EIR_RECV_DONE_MASK 0x00000002UL
  83. /* Xmit error */
  84. #define XEM_EIR_XMIT_ERROR_MASK 0x00000004UL
  85. /* Recv error */
  86. #define XEM_EIR_RECV_ERROR_MASK 0x00000008UL
  87. /* Xmit status fifo empty */
  88. #define XEM_EIR_XMIT_SFIFO_EMPTY_MASK 0x00000010UL
  89. /* Recv length fifo empty */
  90. #define XEM_EIR_RECV_LFIFO_EMPTY_MASK 0x00000020UL
  91. /* Xmit length fifo full */
  92. #define XEM_EIR_XMIT_LFIFO_FULL_MASK 0x00000040UL
  93. /* Recv length fifo overrun */
  94. #define XEM_EIR_RECV_LFIFO_OVER_MASK 0x00000080UL
  95. /* Recv length fifo underrun */
  96. #define XEM_EIR_RECV_LFIFO_UNDER_MASK 0x00000100UL
  97. /* Xmit status fifo overrun */
  98. #define XEM_EIR_XMIT_SFIFO_OVER_MASK 0x00000200UL
  99. /* Transmit status fifo underrun */
  100. #define XEM_EIR_XMIT_SFIFO_UNDER_MASK 0x00000400UL
  101. /* Transmit length fifo overrun */
  102. #define XEM_EIR_XMIT_LFIFO_OVER_MASK 0x00000800UL
  103. /* Transmit length fifo underrun */
  104. #define XEM_EIR_XMIT_LFIFO_UNDER_MASK 0x00001000UL
  105. /* Transmit pause pkt received */
  106. #define XEM_EIR_XMIT_PAUSE_MASK 0x00002000UL
  107. /*
  108. * EMAC Control Register (ECR)
  109. */
  110. /* Full duplex mode */
  111. #define XEM_ECR_FULL_DUPLEX_MASK 0x80000000UL
  112. /* Reset transmitter */
  113. #define XEM_ECR_XMIT_RESET_MASK 0x40000000UL
  114. /* Enable transmitter */
  115. #define XEM_ECR_XMIT_ENABLE_MASK 0x20000000UL
  116. /* Reset receiver */
  117. #define XEM_ECR_RECV_RESET_MASK 0x10000000UL
  118. /* Enable receiver */
  119. #define XEM_ECR_RECV_ENABLE_MASK 0x08000000UL
  120. /* Enable PHY */
  121. #define XEM_ECR_PHY_ENABLE_MASK 0x04000000UL
  122. /* Enable xmit pad insert */
  123. #define XEM_ECR_XMIT_PAD_ENABLE_MASK 0x02000000UL
  124. /* Enable xmit FCS insert */
  125. #define XEM_ECR_XMIT_FCS_ENABLE_MASK 0x01000000UL
  126. /* Enable unicast addr */
  127. #define XEM_ECR_UNICAST_ENABLE_MASK 0x00020000UL
  128. /* Enable broadcast addr */
  129. #define XEM_ECR_BROAD_ENABLE_MASK 0x00008000UL
  130. /*
  131. * Transmit Status Register (TSR)
  132. */
  133. /* Transmit excess deferral */
  134. #define XEM_TSR_EXCESS_DEFERRAL_MASK 0x80000000UL
  135. /* Transmit late collision */
  136. #define XEM_TSR_LATE_COLLISION_MASK 0x01000000UL
  137. #define ENET_MAX_MTU PKTSIZE
  138. #define ENET_ADDR_LENGTH 6
  139. static unsigned int etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
  140. static u8 emacaddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 0x01 };
  141. static xemac emac;
  142. void eth_halt(void)
  143. {
  144. debug ("eth_halt\n");
  145. }
  146. int eth_init(bd_t * bis)
  147. {
  148. uchar enetaddr[6];
  149. u32 helpreg;
  150. debug ("EMAC Initialization Started\n\r");
  151. if (emac.isstarted) {
  152. puts("Emac is started\n");
  153. return 0;
  154. }
  155. memset (&emac, 0, sizeof (xemac));
  156. emac.baseaddress = XILINX_EMAC_BASEADDR;
  157. /* Setting up FIFOs */
  158. emac.recvfifo.regbaseaddress = emac.baseaddress +
  159. XEM_PFIFO_RXREG_OFFSET;
  160. emac.recvfifo.databaseaddress = emac.baseaddress +
  161. XEM_PFIFO_RXDATA_OFFSET;
  162. out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
  163. emac.sendfifo.regbaseaddress = emac.baseaddress +
  164. XEM_PFIFO_TXREG_OFFSET;
  165. emac.sendfifo.databaseaddress = emac.baseaddress +
  166. XEM_PFIFO_TXDATA_OFFSET;
  167. out_be32 (emac.sendfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
  168. /* Reset the entire IPIF */
  169. out_be32 (emac.baseaddress + XIIF_V123B_RESETR_OFFSET,
  170. XIIF_V123B_RESET_MASK);
  171. /* Stopping EMAC for setting up MAC */
  172. helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET);
  173. helpreg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
  174. out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
  175. if (!eth_getenv_enetaddr("ethaddr", enetaddr)) {
  176. memcpy(enetaddr, emacaddr, ENET_ADDR_LENGTH);
  177. eth_setenv_enetaddr("ethaddr", enetaddr);
  178. }
  179. /* Set the device station address high and low registers */
  180. helpreg = (enetaddr[0] << 8) | enetaddr[1];
  181. out_be32 (emac.baseaddress + XEM_SAH_OFFSET, helpreg);
  182. helpreg = (enetaddr[2] << 24) | (enetaddr[3] << 16) |
  183. (enetaddr[4] << 8) | enetaddr[5];
  184. out_be32 (emac.baseaddress + XEM_SAL_OFFSET, helpreg);
  185. helpreg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK |
  186. XEM_ECR_FULL_DUPLEX_MASK | XEM_ECR_XMIT_FCS_ENABLE_MASK |
  187. XEM_ECR_XMIT_PAD_ENABLE_MASK | XEM_ECR_PHY_ENABLE_MASK;
  188. out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
  189. emac.isstarted = 1;
  190. /* Enable the transmitter, and receiver */
  191. helpreg = in_be32 (emac.baseaddress + XEM_ECR_OFFSET);
  192. helpreg &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK);
  193. helpreg |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
  194. out_be32 (emac.baseaddress + XEM_ECR_OFFSET, helpreg);
  195. printf("EMAC Initialization complete\n\r");
  196. return 0;
  197. }
  198. int eth_send(volatile void *ptr, int len)
  199. {
  200. u32 intrstatus;
  201. u32 xmitstatus;
  202. u32 fifocount;
  203. u32 wordcount;
  204. u32 extrabytecount;
  205. u32 *wordbuffer = (u32 *) ptr;
  206. if (len > ENET_MAX_MTU)
  207. len = ENET_MAX_MTU;
  208. /*
  209. * Check for overruns and underruns for the transmit status and length
  210. * FIFOs and make sure the send packet FIFO is not deadlocked.
  211. * Any of these conditions is bad enough that we do not want to
  212. * continue. The upper layer software should reset the device to resolve
  213. * the error.
  214. */
  215. intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
  216. if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
  217. XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
  218. debug ("Transmitting overrun error\n");
  219. return 0;
  220. } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
  221. XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
  222. debug ("Transmitting underrun error\n");
  223. return 0;
  224. } else if (in_be32 (emac.sendfifo.regbaseaddress +
  225. XPF_COUNT_STATUS_REG_OFFSET) & XPF_DEADLOCK_MASK) {
  226. debug ("Transmitting fifo error\n");
  227. return 0;
  228. }
  229. /*
  230. * Before writing to the data FIFO, make sure the length FIFO is not
  231. * full. The data FIFO might not be full yet even though the length FIFO
  232. * is. This avoids an overrun condition on the length FIFO and keeps the
  233. * FIFOs in sync.
  234. *
  235. * Clear the latched LFIFO_FULL bit so next time around the most
  236. * current status is represented
  237. */
  238. if (intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) {
  239. out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
  240. intrstatus & XEM_EIR_XMIT_LFIFO_FULL_MASK);
  241. debug ("Fifo is full\n");
  242. return 0;
  243. }
  244. /* get the count of how many words may be inserted into the FIFO */
  245. fifocount = in_be32 (emac.sendfifo.regbaseaddress +
  246. XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
  247. wordcount = len >> 2;
  248. extrabytecount = len & 0x3;
  249. if (fifocount < wordcount) {
  250. debug ("Sending packet is larger then size of FIFO\n");
  251. return 0;
  252. }
  253. for (fifocount = 0; fifocount < wordcount; fifocount++) {
  254. out_be32 (emac.sendfifo.databaseaddress, wordbuffer[fifocount]);
  255. }
  256. if (extrabytecount > 0) {
  257. u32 lastword = 0;
  258. u8 *extrabytesbuffer = (u8 *) (wordbuffer + wordcount);
  259. if (extrabytecount == 1) {
  260. lastword = extrabytesbuffer[0] << 24;
  261. } else if (extrabytecount == 2) {
  262. lastword = extrabytesbuffer[0] << 24 |
  263. extrabytesbuffer[1] << 16;
  264. } else if (extrabytecount == 3) {
  265. lastword = extrabytesbuffer[0] << 24 |
  266. extrabytesbuffer[1] << 16 |
  267. extrabytesbuffer[2] << 8;
  268. }
  269. out_be32 (emac.sendfifo.databaseaddress, lastword);
  270. }
  271. /* Loop on the MAC's status to wait for any pause to complete */
  272. intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
  273. while ((intrstatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) {
  274. intrstatus = in_be32 ((emac.baseaddress) +
  275. XIIF_V123B_IISR_OFFSET);
  276. /* Clear the pause status from the transmit status register */
  277. out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
  278. intrstatus & XEM_EIR_XMIT_PAUSE_MASK);
  279. }
  280. /*
  281. * Set the MAC's transmit packet length register to tell it to transmit
  282. */
  283. out_be32 (emac.baseaddress + XEM_TPLR_OFFSET, len);
  284. /*
  285. * Loop on the MAC's status to wait for the transmit to complete.
  286. * The transmit status is in the FIFO when the XMIT_DONE bit is set.
  287. */
  288. do {
  289. intrstatus = in_be32 ((emac.baseaddress) +
  290. XIIF_V123B_IISR_OFFSET);
  291. }
  292. while ((intrstatus & XEM_EIR_XMIT_DONE_MASK) == 0);
  293. xmitstatus = in_be32 (emac.baseaddress + XEM_TSR_OFFSET);
  294. if (intrstatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
  295. XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
  296. debug ("Transmitting overrun error\n");
  297. return 0;
  298. } else if (intrstatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
  299. XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
  300. debug ("Transmitting underrun error\n");
  301. return 0;
  302. }
  303. /* Clear the interrupt status register of transmit statuses */
  304. out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
  305. intrstatus & XEM_EIR_XMIT_ALL_MASK);
  306. /*
  307. * Collision errors are stored in the transmit status register
  308. * instead of the interrupt status register
  309. */
  310. if ((xmitstatus & XEM_TSR_EXCESS_DEFERRAL_MASK) ||
  311. (xmitstatus & XEM_TSR_LATE_COLLISION_MASK)) {
  312. debug ("Transmitting collision error\n");
  313. return 0;
  314. }
  315. return 1;
  316. }
  317. int eth_rx(void)
  318. {
  319. u32 pktlength;
  320. u32 intrstatus;
  321. u32 fifocount;
  322. u32 wordcount;
  323. u32 extrabytecount;
  324. u32 lastword;
  325. u8 *extrabytesbuffer;
  326. if (in_be32 (emac.recvfifo.regbaseaddress + XPF_COUNT_STATUS_REG_OFFSET)
  327. & XPF_DEADLOCK_MASK) {
  328. out_be32 (emac.recvfifo.regbaseaddress, XPF_RESET_FIFO_MASK);
  329. debug ("Receiving FIFO deadlock\n");
  330. return 0;
  331. }
  332. /*
  333. * Get the interrupt status to know what happened (whether an error
  334. * occurred and/or whether frames have been received successfully).
  335. * When clearing the intr status register, clear only statuses that
  336. * pertain to receive.
  337. */
  338. intrstatus = in_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET);
  339. /*
  340. * Before reading from the length FIFO, make sure the length FIFO is not
  341. * empty. We could cause an underrun error if we try to read from an
  342. * empty FIFO.
  343. */
  344. if (!(intrstatus & XEM_EIR_RECV_DONE_MASK)) {
  345. /* debug ("Receiving FIFO is empty\n"); */
  346. return 0;
  347. }
  348. /*
  349. * Determine, from the MAC, the length of the next packet available
  350. * in the data FIFO (there should be a non-zero length here)
  351. */
  352. pktlength = in_be32 (emac.baseaddress + XEM_RPLR_OFFSET);
  353. if (!pktlength) {
  354. return 0;
  355. }
  356. /*
  357. * Write the RECV_DONE bit in the status register to clear it. This bit
  358. * indicates the RPLR is non-empty, and we know it's set at this point.
  359. * We clear it so that subsequent entry into this routine will reflect
  360. * the current status. This is done because the non-empty bit is latched
  361. * in the IPIF, which means it may indicate a non-empty condition even
  362. * though there is something in the FIFO.
  363. */
  364. out_be32 ((emac.baseaddress) + XIIF_V123B_IISR_OFFSET,
  365. XEM_EIR_RECV_DONE_MASK);
  366. fifocount = in_be32 (emac.recvfifo.regbaseaddress +
  367. XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
  368. if ((fifocount * 4) < pktlength) {
  369. debug ("Receiving FIFO is smaller than packet size.\n");
  370. return 0;
  371. }
  372. wordcount = pktlength >> 2;
  373. extrabytecount = pktlength & 0x3;
  374. for (fifocount = 0; fifocount < wordcount; fifocount++) {
  375. etherrxbuff[fifocount] =
  376. in_be32 (emac.recvfifo.databaseaddress);
  377. }
  378. /*
  379. * if there are extra bytes to handle, read the last word from the FIFO
  380. * and insert the extra bytes into the buffer
  381. */
  382. if (extrabytecount > 0) {
  383. extrabytesbuffer = (u8 *) (etherrxbuff + wordcount);
  384. lastword = in_be32 (emac.recvfifo.databaseaddress);
  385. /*
  386. * one extra byte in the last word, put the byte into the next
  387. * location of the buffer, bytes in a word of the FIFO are
  388. * ordered from most significant byte to least
  389. */
  390. if (extrabytecount == 1) {
  391. extrabytesbuffer[0] = (u8) (lastword >> 24);
  392. } else if (extrabytecount == 2) {
  393. extrabytesbuffer[0] = (u8) (lastword >> 24);
  394. extrabytesbuffer[1] = (u8) (lastword >> 16);
  395. } else if (extrabytecount == 3) {
  396. extrabytesbuffer[0] = (u8) (lastword >> 24);
  397. extrabytesbuffer[1] = (u8) (lastword >> 16);
  398. extrabytesbuffer[2] = (u8) (lastword >> 8);
  399. }
  400. }
  401. NetReceive((uchar *)etherrxbuff, pktlength);
  402. return 1;
  403. }