luminaryif.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. //*****************************************************************************
  2. //
  3. // luminaryif.c - Ethernet Interface File for lwIP TCP/IP Stack
  4. //
  5. //*****************************************************************************
  6. #include <inc/hw_memmap.h>
  7. #include <inc/hw_types.h>
  8. #include <inc/hw_ints.h>
  9. #include <inc/hw_ethernet.h>
  10. #include <driverlib/ethernet.h>
  11. #include <driverlib/interrupt.h>
  12. #include <driverlib/sysctl.h>
  13. #include <driverlib/gpio.h>
  14. #include <driverlib/flash.h>
  15. #include <lwip/stats.h>
  16. #include <netif/ethernetif.h>
  17. #include "lwipopts.h"
  18. #include "luminaryif.h"
  19. #define MAX_ADDR_LEN 6
  20. struct net_device
  21. {
  22. /* inherit from ethernet device */
  23. struct eth_device parent;
  24. /* interface address info. */
  25. rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
  26. };
  27. static struct net_device luminaryif_dev_entry;
  28. static struct net_device *luminaryif_dev = &luminaryif_dev_entry;
  29. static struct rt_semaphore tx_sem;
  30. //*****************************************************************************
  31. //
  32. // Sanity Check: This module will NOT work if the following defines
  33. // are incorrect.
  34. //
  35. //*****************************************************************************
  36. #if (PBUF_LINK_HLEN != 16)
  37. #error "Incorrect PBUF_LINK_HLEN specified!"
  38. #endif
  39. #if (ETH_PAD_SIZE != 2)
  40. #error "Incorrect ETH_PAD_SIZE specified!"
  41. #endif
  42. #if (PBUF_POOL_BUFSIZE % 4)
  43. #error "PBUF_POOL_BUFSIZE must be modulo 4!"
  44. #endif
  45. /* RT-Thread Device Interface */
  46. /* initialize the interface */
  47. //*****************************************************************************
  48. //
  49. // Low-Level initialization function for the Ethernet Controller.
  50. //
  51. //*****************************************************************************
  52. rt_err_t luminaryif_init(rt_device_t dev)
  53. {
  54. unsigned long ulTemp;
  55. //
  56. // Disable all Ethernet Interrupts.
  57. //
  58. EthernetIntDisable(ETH_BASE, (ETH_INT_PHY | ETH_INT_MDIO | ETH_INT_RXER |
  59. ETH_INT_RXOF | ETH_INT_TX | ETH_INT_TXER |
  60. ETH_INT_RX));
  61. ulTemp = EthernetIntStatus(ETH_BASE, false);
  62. EthernetIntClear(ETH_BASE, ulTemp);
  63. //
  64. // Initialize the Ethernet Controller.
  65. //
  66. EthernetInitExpClk(ETH_BASE, SysCtlClockGet());
  67. //
  68. // Configure the Ethernet Controller for normal operation.
  69. // - Enable TX Duplex Mode
  70. // - Enable TX Padding
  71. // - Enable TX CRC Generation
  72. // - Enable reception of multicast packets
  73. //
  74. EthernetConfigSet(ETH_BASE, (ETH_CFG_TX_DPLXEN |
  75. ETH_CFG_TX_CRCEN | ETH_CFG_TX_PADEN | ETH_CFG_RX_AMULEN));
  76. //
  77. // Enable the Ethernet Controller transmitter and receiver.
  78. //
  79. EthernetEnable(ETH_BASE);
  80. //
  81. // Enable the Ethernet Interrupt handler.
  82. //
  83. IntEnable(INT_ETH);
  84. //
  85. // Enable Ethernet TX and RX Packet Interrupts.
  86. //
  87. EthernetIntEnable(ETH_BASE, ETH_INT_RX | ETH_INT_TX);
  88. return RT_EOK;
  89. }
  90. void luminaryif_isr(void)
  91. {
  92. unsigned long ulTemp;
  93. //
  94. // Read and Clear the interrupt.
  95. //
  96. ulTemp = EthernetIntStatus(ETH_BASE, false);
  97. EthernetIntClear(ETH_BASE, ulTemp);
  98. //
  99. // Check to see if an RX Interrupt has occured.
  100. //
  101. if (ulTemp & ETH_INT_RX)
  102. {
  103. //
  104. // Indicate that a packet has been received.
  105. //
  106. rt_err_t result;
  107. /* a frame has been received */
  108. result = eth_device_ready((struct eth_device *)&(luminaryif_dev->parent));
  109. if (result != RT_EOK)
  110. rt_set_errno(-RT_ERROR);
  111. //
  112. // Disable Ethernet RX Interrupt.
  113. //
  114. EthernetIntDisable(ETH_BASE, ETH_INT_RX);
  115. }
  116. if (ulTemp & ETH_INT_TX)
  117. {
  118. /* A frame has been transmitted. */
  119. rt_sem_release(&tx_sem);
  120. }
  121. }
  122. /* control the interface */
  123. rt_err_t luminaryif_control(rt_device_t dev, int cmd, void *args)
  124. {
  125. switch (cmd)
  126. {
  127. case NIOCTL_GADDR:
  128. /* get mac address */
  129. if (args)
  130. rt_memcpy(args, luminaryif_dev_entry.dev_addr, 6);
  131. else
  132. return -RT_ERROR;
  133. break;
  134. default:
  135. break;
  136. }
  137. return RT_EOK;
  138. }
  139. /* Open the ethernet interface */
  140. rt_err_t luminaryif_open(rt_device_t dev, rt_uint16_t oflag)
  141. {
  142. return RT_EOK;
  143. }
  144. /* Close the interface */
  145. rt_err_t luminaryif_close(rt_device_t dev)
  146. {
  147. return RT_EOK;
  148. }
  149. /* Read */
  150. rt_size_t luminaryif_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  151. {
  152. rt_set_errno(-RT_ENOSYS);
  153. return 0;
  154. }
  155. /* Write */
  156. rt_size_t luminaryif_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  157. {
  158. rt_set_errno(-RT_ENOSYS);
  159. return 0;
  160. }
  161. //****************************************************************************
  162. //
  163. // Low-Level transmit routine. Should do the actual transmission of the
  164. // packet. The packet is contained in the pbuf that is passed to the function.
  165. // This pbuf might be chained.
  166. //
  167. //****************************************************************************
  168. rt_err_t luminaryif_tx(rt_device_t dev, struct pbuf *p)
  169. {
  170. int iBuf;
  171. unsigned char *pucBuf;
  172. unsigned long *pulBuf;
  173. struct pbuf *q;
  174. int iGather;
  175. unsigned long ulGather;
  176. unsigned char *pucGather;
  177. unsigned long ulTemp;
  178. /* lock tx operation */
  179. rt_sem_take(&tx_sem, RT_WAITING_FOREVER);
  180. //
  181. // Wait for space available in the TX FIFO.
  182. //
  183. while (!EthernetSpaceAvail(ETH_BASE))
  184. {
  185. }
  186. //
  187. // Fill in the first two bytes of the payload data (configured as padding
  188. // with ETH_PAD_SIZE = 2) with the total length of the payload data
  189. // (minus the Ethernet MAC layer header).
  190. //
  191. *((unsigned short *)(p->payload)) = p->tot_len - 16;
  192. //
  193. // Initialize the gather register.
  194. //
  195. iGather = 0;
  196. pucGather = (unsigned char *)&ulGather;
  197. ulGather = 0;
  198. //
  199. // Copy data from the pbuf(s) into the TX Fifo.
  200. //
  201. for (q = p; q != NULL; q = q->next)
  202. {
  203. //
  204. // Intialize a char pointer and index to the pbuf payload data.
  205. //
  206. pucBuf = (unsigned char *)q->payload;
  207. iBuf = 0;
  208. //
  209. // If the gather buffer has leftover data from a previous pbuf
  210. // in the chain, fill it up and write it to the Tx FIFO.
  211. //
  212. while ((iBuf < q->len) && (iGather != 0))
  213. {
  214. //
  215. // Copy a byte from the pbuf into the gather buffer.
  216. //
  217. pucGather[iGather] = pucBuf[iBuf++];
  218. //
  219. // Increment the gather buffer index modulo 4.
  220. //
  221. iGather = ((iGather + 1) % 4);
  222. }
  223. //
  224. // If the gather index is 0 and the pbuf index is non-zero,
  225. // we have a gather buffer to write into the Tx FIFO.
  226. //
  227. if ((iGather == 0) && (iBuf != 0))
  228. {
  229. HWREG(ETH_BASE + MAC_O_DATA) = ulGather;
  230. ulGather = 0;
  231. }
  232. //
  233. // Copy words of pbuf data into the Tx FIFO, but don't go past
  234. // the end of the pbuf.
  235. //
  236. if ((iBuf % 4) != 0)
  237. {
  238. while ((iBuf + 4) <= q->len)
  239. {
  240. ulTemp = (pucBuf[iBuf++] << 0);
  241. ulTemp |= (pucBuf[iBuf++] << 8);
  242. ulTemp |= (pucBuf[iBuf++] << 16);
  243. ulTemp |= (pucBuf[iBuf++] << 24);
  244. HWREG(ETH_BASE + MAC_O_DATA) = ulTemp;
  245. }
  246. }
  247. else
  248. {
  249. //
  250. // Initialze a long pointer into the pbuf for 32-bit access.
  251. //
  252. pulBuf = (unsigned long *)&pucBuf[iBuf];
  253. while ((iBuf + 4) <= q->len)
  254. {
  255. HWREG(ETH_BASE + MAC_O_DATA) = *pulBuf++;
  256. iBuf += 4;
  257. }
  258. }
  259. //
  260. // Check if leftover data in the pbuf and save it in the gather
  261. // buffer for the next time.
  262. //
  263. while (iBuf < q->len)
  264. {
  265. //
  266. // Copy a byte from the pbuf into the gather buffer.
  267. //
  268. pucGather[iGather] = pucBuf[iBuf++];
  269. //
  270. // Increment the gather buffer index modulo 4.
  271. //
  272. iGather = ((iGather + 1) % 4);
  273. }
  274. }
  275. //
  276. // Send any leftover data to the FIFO.
  277. //
  278. HWREG(ETH_BASE + MAC_O_DATA) = ulGather;
  279. //
  280. // Wakeup the transmitter.
  281. //
  282. HWREG(ETH_BASE + MAC_O_TR) = MAC_TR_NEWTX;
  283. #if LINK_STATS
  284. lwip_stats.link.xmit++;
  285. #endif
  286. return (ERR_OK);
  287. }
  288. //*****************************************************************************
  289. //
  290. // Low-Level receive routine. Should allocate a pbuf and transfer the bytes
  291. // of the incoming packet from the interface into the pbuf.
  292. //
  293. //*****************************************************************************
  294. struct pbuf *luminaryif_rx(rt_device_t dev)
  295. {
  296. struct pbuf *p, *q;
  297. u16_t len;
  298. unsigned long ulTemp;
  299. int i;
  300. unsigned long *ptr;
  301. if (!EthernetPacketAvail(ETH_BASE))
  302. {
  303. //
  304. // Enable Ethernet RX Interrupt.
  305. //
  306. EthernetIntEnable(ETH_BASE, ETH_INT_RX);
  307. return (NULL);
  308. }
  309. //
  310. // Obtain the size of the packet and put it into the "len" variable.
  311. // Note: The length returned in the FIFO length position includes the
  312. // two bytes for the length + the 4 bytes for the FCS.
  313. //
  314. ulTemp = HWREG(ETH_BASE + MAC_O_DATA);
  315. len = ulTemp & 0xFFFF;
  316. //
  317. // We allocate a pbuf chain of pbufs from the pool.
  318. //
  319. p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM);
  320. if (p != NULL)
  321. {
  322. //
  323. // Place the first word into the first pbuf location.
  324. //
  325. *(unsigned long *)p->payload = ulTemp;
  326. p->payload = (char *)(p->payload) + 4;
  327. p->len -= 4;
  328. //
  329. // Process all but the last buffer in the pbuf chain.
  330. //
  331. q = p;
  332. while (q != NULL)
  333. {
  334. //
  335. // Setup a byte pointer into the payload section of the pbuf.
  336. //
  337. ptr = q->payload;
  338. //
  339. // Read data from FIFO into the current pbuf
  340. // (assume pbuf length is modulo 4)
  341. //
  342. for (i = 0; i < q->len; i += 4)
  343. {
  344. *ptr++ = HWREG(ETH_BASE + MAC_O_DATA);
  345. }
  346. //
  347. // Link in the next pbuf in the chain.
  348. //
  349. q = q->next;
  350. }
  351. //
  352. // Restore the first pbuf parameters to their original values.
  353. //
  354. p->payload = (char *)(p->payload) - 4;
  355. p->len += 4;
  356. #if LINK_STATS
  357. lwip_stats.link.recv++;
  358. #endif
  359. }
  360. else
  361. {
  362. //
  363. // Just read all of the remaining data from the FIFO and dump it.
  364. //
  365. for (i = 4; i < len; i += 4)
  366. {
  367. ulTemp = HWREG(ETH_BASE + MAC_O_DATA);
  368. }
  369. #if LINK_STATS
  370. lwip_stats.link.memerr++;
  371. lwip_stats.link.drop++;
  372. #endif
  373. //
  374. // Enable Ethernet RX Interrupt.
  375. //
  376. EthernetIntEnable(ETH_BASE, ETH_INT_RX);
  377. }
  378. return (p);
  379. }
  380. int rt_hw_luminaryif_init(void)
  381. {
  382. rt_err_t result;
  383. unsigned long ulUser0, ulUser1;
  384. /* Enable and Reset the Ethernet Controller. */
  385. SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
  386. SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
  387. /*
  388. Enable Port F for Ethernet LEDs.
  389. LED0 Bit 3 Output
  390. LED1 Bit 2 Output
  391. */
  392. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  393. GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3, GPIO_DIR_MODE_HW);
  394. GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3,
  395. GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
  396. FlashUserSet(0x12345678, 0x12345678);
  397. /* Configure the hardware MAC address */
  398. FlashUserGet(&ulUser0, &ulUser1);
  399. if ((ulUser0 == 0xffffffff) || (ulUser1 == 0xffffffff))
  400. {
  401. rt_kprintf("Fatal error in geting MAC address\n");
  402. }
  403. /* init rt-thread device interface */
  404. luminaryif_dev_entry.parent.parent.init = luminaryif_init;
  405. luminaryif_dev_entry.parent.parent.open = luminaryif_open;
  406. luminaryif_dev_entry.parent.parent.close = luminaryif_close;
  407. luminaryif_dev_entry.parent.parent.read = luminaryif_read;
  408. luminaryif_dev_entry.parent.parent.write = luminaryif_write;
  409. luminaryif_dev_entry.parent.parent.control = luminaryif_control;
  410. luminaryif_dev_entry.parent.eth_rx = luminaryif_rx;
  411. luminaryif_dev_entry.parent.eth_tx = luminaryif_tx;
  412. /*
  413. Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
  414. address needed to program the hardware registers, then program the MAC
  415. address into the Ethernet Controller registers.
  416. */
  417. luminaryif_dev_entry.dev_addr[0] = ((ulUser0 >> 0) & 0xff);
  418. luminaryif_dev_entry.dev_addr[1] = ((ulUser0 >> 8) & 0xff);
  419. luminaryif_dev_entry.dev_addr[2] = ((ulUser0 >> 16) & 0xff);
  420. luminaryif_dev_entry.dev_addr[3] = ((ulUser1 >> 0) & 0xff);
  421. luminaryif_dev_entry.dev_addr[4] = ((ulUser1 >> 8) & 0xff);
  422. luminaryif_dev_entry.dev_addr[5] = ((ulUser1 >> 16) & 0xff);
  423. /* Program the hardware with it's MAC address (for filtering). */
  424. EthernetMACAddrSet(ETH_BASE, luminaryif_dev_entry.dev_addr);
  425. rt_sem_init(&tx_sem, "emac", 1, RT_IPC_FLAG_FIFO);
  426. result = eth_device_init(&(luminaryif_dev->parent), "E0");
  427. return result;
  428. }