omapl138_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file omapl138_eth_driver.c
3  * @brief OMAP-L138 Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "soc_omapl138.h"
36 #include "hw_types.h"
37 #include "hw_syscfg0_omapl138.h"
38 #include "hw_emac.h"
39 #include "hw_emac_ctrl.h"
40 #include "hw_mdio.h"
41 #include "cache.h"
42 #include "interrupt.h"
43 #include "psc.h"
44 #include "core/net.h"
46 #include "debug.h"
47 
48 //MDIO input clock frequency
49 #define MDIO_INPUT_CLK 75000000
50 //MDIO output clock frequency
51 #define MDIO_OUTPUT_CLK 1000000
52 
53 //Underlying network interface
54 static NetInterface *nicDriverInterface;
55 
56 //IAR EWARM compiler?
57 #if defined(__ICCARM__)
58 
59 //Transmit buffer
60 #pragma data_alignment = 4
61 #pragma location = OMAPL138_ETH_RAM_SECTION
63 //Receive buffer
64 #pragma data_alignment = 4
65 #pragma location = OMAPL138_ETH_RAM_SECTION
67 //Transmit buffer descriptors
68 #pragma data_alignment = 4
69 #pragma location = OMAPL138_ETH_RAM_CPPI_SECTION
71 //Receive buffer descriptors
72 #pragma data_alignment = 4
73 #pragma location = OMAPL138_ETH_RAM_CPPI_SECTION
75 
76 //GCC compiler?
77 #else
78 
79 //Transmit buffer
81  __attribute__((aligned(4), __section__(OMAPL138_ETH_RAM_SECTION)));
82 //Receive buffer
84  __attribute__((aligned(4), __section__(OMAPL138_ETH_RAM_SECTION)));
85 //Transmit buffer descriptors
87  __attribute__((aligned(4), __section__(OMAPL138_ETH_RAM_CPPI_SECTION)));
88 //Receive buffer descriptors
90  __attribute__((aligned(4), __section__(OMAPL138_ETH_RAM_CPPI_SECTION)));
91 
92 #endif
93 
94 //Pointer to the current TX buffer descriptor
95 static Omapl138TxBufferDesc *txCurBufferDesc;
96 //Pointer to the current RX buffer descriptor
97 static Omapl138RxBufferDesc *rxCurBufferDesc;
98 
99 
100 /**
101  * @brief OMAP-L138 Ethernet MAC driver
102  **/
103 
105 {
107  ETH_MTU,
118  FALSE,
119  TRUE,
120  TRUE,
121  FALSE
122 };
123 
124 
125 /**
126  * @brief OMAP-L138 Ethernet MAC initialization
127  * @param[in] interface Underlying network interface
128  * @return Error code
129  **/
130 
132 {
133  error_t error;
134  uint_t channel;
135  uint32_t temp;
136 
137  //Debug message
138  TRACE_INFO("Initializing OMAP-L138 Ethernet MAC...\r\n");
139 
140  //Save underlying network interface
141  nicDriverInterface = interface;
142 
143  //Enable EMAC module
144  PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_EMAC,
145  PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
146 
147  //Select the interface mode (MII/RMII) and configure pin muxing
148  omapl138EthInitGpio(interface);
149 
150  //Reset the EMAC control module
151  EMAC_CTRL_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
152  //Wait for the reset to complete
153  while((EMAC_CTRL_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
154  {
155  }
156 
157  //Reset the EMAC module
158  EMAC_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
159  //Wait for the reset to complete
160  while((EMAC_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
161  {
162  }
163 
164  //Calculate the MDC clock divider to be used
165  temp = (MDIO_INPUT_CLK / MDIO_OUTPUT_CLK) - 1;
166 
167  //Initialize MDIO interface
168  MDIO_CONTROL_R = MDIO_CONTROL_ENABLE |
169  MDIO_CONTROL_FAULTENB | (temp & MDIO_CONTROL_CLKDIV);
170 
171  //Valid Ethernet PHY or switch driver?
172  if(interface->phyDriver != NULL)
173  {
174  //Ethernet PHY initialization
175  error = interface->phyDriver->init(interface);
176  }
177  else if(interface->switchDriver != NULL)
178  {
179  //Ethernet switch initialization
180  error = interface->switchDriver->init(interface);
181  }
182  else
183  {
184  //The interface is not properly configured
185  error = ERROR_FAILURE;
186  }
187 
188  //Any error to report?
189  if(error)
190  {
191  return error;
192  }
193 
194  //Clear the control registers
195  EMAC_MACCONTROL_R = 0;
196  EMAC_RXCONTROL_R = 0;
197  EMAC_TXCONTROL_R = 0;
198 
199  //Initialize all 16 header descriptor pointer registers to 0
200  for(channel = EMAC_CH0; channel <= EMAC_CH7; channel++)
201  {
202  //TX head descriptor pointer
203  EMAC_TXHDP_R(channel) = 0;
204  //TX completion pointer
205  EMAC_TXCP_R(channel) = 0;
206  //RX head descriptor pointer
207  EMAC_RXHDP_R(channel) = 0;
208  //RX completion pointer
209  EMAC_RXCP_R(channel) = 0;
210  }
211 
212  //Set the upper 32 bits of the source MAC address
213  EMAC_MACSRCADDRHI_R = interface->macAddr.b[0] |
214  (interface->macAddr.b[1] << 8) |
215  (interface->macAddr.b[2] << 16) |
216  (interface->macAddr.b[3] << 24);
217 
218  //Set the lower 16 bits of the source MAC address
219  EMAC_MACSRCADDRLO_R = interface->macAddr.b[4] |
220  (interface->macAddr.b[5] << 8);
221 
222  //Write the channel number to the MAC index register
224 
225  //Set the upper 32 bits of the destination MAC address
226  EMAC_MACADDRHI_R = interface->macAddr.b[0] |
227  (interface->macAddr.b[1] << 8) |
228  (interface->macAddr.b[2] << 16) |
229  (interface->macAddr.b[3] << 24);
230 
231  //Set the lower 16 bits of the destination MAC address
232  temp = interface->macAddr.b[4] |
233  (interface->macAddr.b[5] << 8);
234 
235  //Use the current MAC address to match incoming packet addresses
236  EMAC_MACADDRLO_R = EMAC_MACADDRLO_VALID | EMAC_MACADDRLO_MATCHFILT |
237  (EMAC_CH0 << EMAC_MACADDRLO_CHANNEL_SHIFT) | temp;
238 
239  //Be sure to program all eight MAC address registers, whether the
240  //receive channel is to be enabled or not
241  for(channel = EMAC_CH1; channel <= EMAC_CH7; channel++)
242  {
243  //Write the channel number to the MAC index register
244  EMAC_MACINDEX_R = channel;
245  //The MAC address is not valid
246  EMAC_MACADDRLO_R = (channel << EMAC_MACADDRLO_CHANNEL_SHIFT);
247  }
248 
249  //Clear the MAC address hash registers
250  EMAC_MACHASH1_R = 0;
251  EMAC_MACHASH2_R = 0;
252 
253  //The RX buffer offset must be initialized to zero
255 
256  //Clear all unicast channels
257  EMAC_RXUNICASTCLEAR_R = 0xFF;
258 
259  //Accept unicast frames
260  EMAC_RXUNICASTSET_R |= (1 << EMAC_CH0);
261 
262  //Received CRC is transferred to memory for all channels
263  EMAC_RXMBPENABLE_R = EMAC_RXMBPENABLE_RXPASSCRC;
264 
265  //Accept broadcast frames
266  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXBROADEN |
267  (EMAC_CH0 << EMAC_RXMBPENABLE_RXBROADCH_SHIFT);
268 
269  //Accept hash matching multicast frames
270  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXMULTEN |
271  (EMAC_CH0 << EMAC_RXMBPENABLE_RXMULTCH_SHIFT);
272 
273  //Register interrupt handlers
274  IntRegister(SYS_INT_C0_TX, omapl138EthTxIrqHandler);
275  IntRegister(SYS_INT_C0_RX, omapl138EthRxIrqHandler);
276 
277  //Set the channel number for the TX interrupt
278  IntChannelSet(SYS_INT_C0_TX, OMAPL138_ETH_TX_IRQ_CHANNEL);
279  //Set the channel number for the RX interrupt
280  IntChannelSet(SYS_INT_C0_RX, OMAPL138_ETH_RX_IRQ_CHANNEL);
281 
282  //Clear all unused channel interrupt bits
283  EMAC_TXINTMASKCLEAR_R = 0xFF;
284  EMAC_RXINTMASKCLEAR_R = 0xFF;
285 
286  //Enable the receive and transmit channel interrupt bits
287  EMAC_TXINTMASKSET_R = (1 << EMAC_CH0);
288  EMAC_RXINTMASKSET_R = (1 << EMAC_CH0);
289 
290  //Configure TX and RX buffer descriptors
291  omapl138EthInitBufferDesc(interface);
292 
293  //Write the RX DMA head descriptor pointer
294  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
295 
296  //Enable the receive and transmit DMA controllers
297  EMAC_TXCONTROL_R = EMAC_TXCONTROL_TXEN;
298  EMAC_RXCONTROL_R = EMAC_RXCONTROL_RXEN;
299 
300  //Enable TX and RX
301  EMAC_MACCONTROL_R = EMAC_MACCONTROL_GMIIEN;
302 
303  //Enable TX and RX completion interrupts
306 
307  //Accept any packets from the upper layer
308  osSetEvent(&interface->nicTxEvent);
309 
310  //Successful initialization
311  return NO_ERROR;
312 }
313 
314 
315 /**
316  * @brief GPIO configuration
317  * @param[in] interface Underlying network interface
318  **/
319 
320 __weak_func void omapl138EthInitGpio(NetInterface *interface)
321 {
322 //TMDSLCDK138 board?
323 #if defined(USE_TMDSLCDK138)
324  uint32_t temp;
325 
326  //Enable GPIO module
327  PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO,
328  PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
329 
330  //Configure MII_TXD0, MII_TXD1, MII_TXD2, MII_TXD3, MII_COL, MII_TXCLK and MII_TXEN
331  temp = SYSCFG0_PINMUX_R(2) & ~(SYSCFG_PINMUX2_PINMUX2_31_28 |
332  SYSCFG_PINMUX2_PINMUX2_27_24 | SYSCFG_PINMUX2_PINMUX2_23_20 |
333  SYSCFG_PINMUX2_PINMUX2_19_16 | SYSCFG_PINMUX2_PINMUX2_15_12 |
334  SYSCFG_PINMUX2_PINMUX2_11_8 | SYSCFG_PINMUX2_PINMUX2_7_4);
335 
336  SYSCFG0_PINMUX_R(2) = temp |
337  (SYSCFG_PINMUX2_PINMUX2_31_28_MII_TXD0 << SYSCFG_PINMUX2_PINMUX2_31_28_SHIFT) |
338  (SYSCFG_PINMUX2_PINMUX2_27_24_MII_TXD1 << SYSCFG_PINMUX2_PINMUX2_27_24_SHIFT) |
339  (SYSCFG_PINMUX2_PINMUX2_23_20_MII_TXD2 << SYSCFG_PINMUX2_PINMUX2_23_20_SHIFT) |
340  (SYSCFG_PINMUX2_PINMUX2_19_16_MII_TXD3 << SYSCFG_PINMUX2_PINMUX2_19_16_SHIFT) |
341  (SYSCFG_PINMUX2_PINMUX2_15_12_MII_COL << SYSCFG_PINMUX2_PINMUX2_15_12_SHIFT) |
342  (SYSCFG_PINMUX2_PINMUX2_11_8_MII_TXCLK << SYSCFG_PINMUX2_PINMUX2_11_8_SHIFT) |
343  (SYSCFG_PINMUX2_PINMUX2_7_4_MII_TXEN << SYSCFG_PINMUX2_PINMUX2_7_4_SHIFT);
344 
345  //Configure MII_RXD0, MII_RXD1, MII_RXD2, MII_RXD3, MII_CRS, MII_RXER, MII_RXDV and RXCLK
346  temp = SYSCFG0_PINMUX_R(3) & ~(SYSCFG_PINMUX3_PINMUX3_31_28 |
347  SYSCFG_PINMUX3_PINMUX3_27_24 | SYSCFG_PINMUX3_PINMUX3_23_20 |
348  SYSCFG_PINMUX3_PINMUX3_19_16 | SYSCFG_PINMUX3_PINMUX3_15_12 |
349  SYSCFG_PINMUX3_PINMUX3_11_8 | SYSCFG_PINMUX3_PINMUX3_7_4 |
350  SYSCFG_PINMUX3_PINMUX3_3_0);
351 
352  SYSCFG0_PINMUX_R(3) = temp |
353  (SYSCFG_PINMUX3_PINMUX3_31_28_MII_RXD0 << SYSCFG_PINMUX3_PINMUX3_31_28_SHIFT) |
354  (SYSCFG_PINMUX3_PINMUX3_27_24_MII_RXD1 << SYSCFG_PINMUX3_PINMUX3_27_24_SHIFT) |
355  (SYSCFG_PINMUX3_PINMUX3_23_20_MII_RXD2 << SYSCFG_PINMUX3_PINMUX3_23_20_SHIFT) |
356  (SYSCFG_PINMUX3_PINMUX3_19_16_MII_RXD3 << SYSCFG_PINMUX3_PINMUX3_19_16_SHIFT) |
357  (SYSCFG_PINMUX3_PINMUX3_15_12_MII_CRS << SYSCFG_PINMUX3_PINMUX3_15_12_SHIFT) |
358  (SYSCFG_PINMUX3_PINMUX3_11_8_MII_RXER << SYSCFG_PINMUX3_PINMUX3_11_8_SHIFT) |
359  (SYSCFG_PINMUX3_PINMUX3_7_4_MII_RXDV << SYSCFG_PINMUX3_PINMUX3_7_4_SHIFT) |
360  (SYSCFG_PINMUX3_PINMUX3_3_0_MII_RXCLK << SYSCFG_PINMUX3_PINMUX3_3_0_SHIFT);
361 
362  //Configure MDIO and MDCLK
363  temp = SYSCFG0_PINMUX_R(4) & ~(SYSCFG_PINMUX4_PINMUX4_3_0 |
364  SYSCFG_PINMUX4_PINMUX4_7_4);
365 
366  SYSCFG0_PINMUX_R(4) = temp |
367  (SYSCFG_PINMUX4_PINMUX4_7_4_MDIO_D << SYSCFG_PINMUX4_PINMUX4_7_4_SHIFT) |
368  (SYSCFG_PINMUX4_PINMUX4_3_0_MDIO_CLK << SYSCFG_PINMUX4_PINMUX4_3_0_SHIFT);
369 
370  //Select MII interface mode
371  SYSCFG0_CFGCHIP3_R &= ~SYSCFG_CFGCHIP3_RMII_SEL;
372 #endif
373 }
374 
375 
376 /**
377  * @brief Initialize buffer descriptor lists
378  * @param[in] interface Underlying network interface
379  **/
380 
382 {
383  uint_t i;
384  uint_t nextIndex;
385  uint_t prevIndex;
386 
387  //Initialize TX buffer descriptor list
388  for(i = 0; i < OMAPL138_ETH_TX_BUFFER_COUNT; i++)
389  {
390  //Index of the next buffer
391  nextIndex = (i + 1) % OMAPL138_ETH_TX_BUFFER_COUNT;
392  //Index of the previous buffer
394 
395  //Next descriptor pointer
396  txBufferDesc[i].word0 = (uint32_t) NULL;
397  //Buffer pointer
398  txBufferDesc[i].word1 = (uint32_t) txBuffer[i];
399  //Buffer offset and buffer length
400  txBufferDesc[i].word2 = 0;
401  //Status flags and packet length
402  txBufferDesc[i].word3 = 0;
403 
404  //Form a doubly linked list
405  txBufferDesc[i].next = &txBufferDesc[nextIndex];
406  txBufferDesc[i].prev = &txBufferDesc[prevIndex];
407  }
408 
409  //Point to the very first descriptor
410  txCurBufferDesc = &txBufferDesc[0];
411 
412  //Mark the end of the queue
413  txCurBufferDesc->prev->word3 = EMAC_TX_WORD3_SOP |
415 
416  //Initialize RX buffer descriptor list
417  for(i = 0; i < OMAPL138_ETH_RX_BUFFER_COUNT; i++)
418  {
419  //Index of the next buffer
420  nextIndex = (i + 1) % OMAPL138_ETH_RX_BUFFER_COUNT;
421  //Index of the previous buffer
423 
424  //Next descriptor pointer
425  rxBufferDesc[i].word0 = (uint32_t) &rxBufferDesc[nextIndex];
426  //Buffer pointer
427  rxBufferDesc[i].word1 = (uint32_t) rxBuffer[i];
428  //Buffer offset and buffer length
429  rxBufferDesc[i].word2 = OMAPL138_ETH_RX_BUFFER_SIZE;
430  //Status flags and packet length
431  rxBufferDesc[i].word3 = EMAC_RX_WORD3_OWNER;
432 
433  //Form a doubly linked list
434  rxBufferDesc[i].next = &rxBufferDesc[nextIndex];
435  rxBufferDesc[i].prev = &rxBufferDesc[prevIndex];
436  }
437 
438  //Point to the very first descriptor
439  rxCurBufferDesc = &rxBufferDesc[0];
440 
441  //Mark the end of the queue
442  rxCurBufferDesc->prev->word0 = (uint32_t) NULL;
443 }
444 
445 
446 /**
447  * @brief OMAP-L138 Ethernet MAC timer handler
448  *
449  * This routine is periodically called by the TCP/IP stack to handle periodic
450  * operations such as polling the link state
451  *
452  * @param[in] interface Underlying network interface
453  **/
454 
456 {
457  //Valid Ethernet PHY or switch driver?
458  if(interface->phyDriver != NULL)
459  {
460  //Handle periodic operations
461  interface->phyDriver->tick(interface);
462  }
463  else if(interface->switchDriver != NULL)
464  {
465  //Handle periodic operations
466  interface->switchDriver->tick(interface);
467  }
468  else
469  {
470  //Just for sanity
471  }
472 
473  //Misqueued buffer condition?
474  if((rxCurBufferDesc->word3 & EMAC_RX_WORD3_OWNER) != 0)
475  {
476  if(EMAC_RXHDP_R(EMAC_CH0) == 0)
477  {
478  //The host acts on the misqueued buffer condition by writing the added
479  //buffer descriptor address to the appropriate RX DMA head descriptor
480  //pointer
481  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
482  }
483  }
484 }
485 
486 
487 /**
488  * @brief Enable interrupts
489  * @param[in] interface Underlying network interface
490  **/
491 
493 {
494  //Enable Ethernet MAC interrupts
495  IntSystemEnable(SYS_INT_C0_TX);
496  IntSystemEnable(SYS_INT_C0_RX);
497 
498  //Valid Ethernet PHY or switch driver?
499  if(interface->phyDriver != NULL)
500  {
501  //Enable Ethernet PHY interrupts
502  interface->phyDriver->enableIrq(interface);
503  }
504  else if(interface->switchDriver != NULL)
505  {
506  //Enable Ethernet switch interrupts
507  interface->switchDriver->enableIrq(interface);
508  }
509  else
510  {
511  //Just for sanity
512  }
513 }
514 
515 
516 /**
517  * @brief Disable interrupts
518  * @param[in] interface Underlying network interface
519  **/
520 
522 {
523  //Disable Ethernet MAC interrupts
524  IntSystemDisable(SYS_INT_C0_TX);
525  IntSystemDisable(SYS_INT_C0_RX);
526 
527  //Valid Ethernet PHY or switch driver?
528  if(interface->phyDriver != NULL)
529  {
530  //Disable Ethernet PHY interrupts
531  interface->phyDriver->disableIrq(interface);
532  }
533  else if(interface->switchDriver != NULL)
534  {
535  //Disable Ethernet switch interrupts
536  interface->switchDriver->disableIrq(interface);
537  }
538  else
539  {
540  //Just for sanity
541  }
542 }
543 
544 
545 /**
546  * @brief Ethernet MAC transmit interrupt
547  **/
548 
550 {
551  bool_t flag;
552  uint32_t status;
553  uint32_t temp;
555 
556  //Interrupt service routine prologue
557  osEnterIsr();
558 
559  //This flag will be set if a higher priority task must be woken
560  flag = FALSE;
561 
562  //Clear system interrupt status
563  IntSystemStatusClear(SYS_INT_C0_TX);
564 
565  //Read the C0TXSTAT register to determine which channels caused the interrupt
566  status = EMAC_CTRL_C0TXSTAT_R;
567 
568  //Packet transmitted on channel 0?
569  if(status & (1 << EMAC_CH0))
570  {
571  //Point to the buffer descriptor
573 
574  //Read the status flags
575  temp = p->word3 & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
577 
578  //Misqueued buffer condition?
580  {
581  //Check whether the next descriptor pointer is non-zero
582  if(p->word0 != 0)
583  {
584  //The host corrects the misqueued buffer condition by writing the
585  //misqueued packet’s buffer descriptor address to the appropriate
586  //TX DMA head descriptor pointer
587  EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) p->word0;
588  }
589  }
590 
591  //Write the TX completion pointer
592  EMAC_TXCP_R(EMAC_CH0) = (uint32_t) p;
593 
594  //Check whether the TX buffer is available for writing
595  if((txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER) == 0)
596  {
597  //Notify the TCP/IP stack that the transmitter is ready to send
598  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
599  }
600  }
601 
602  //Write the DMA end of interrupt vector
604 
605  //Interrupt service routine epilogue
606  osExitIsr(flag);
607 }
608 
609 
610 /**
611  * @brief Ethernet MAC receive interrupt
612  **/
613 
615 {
616  bool_t flag;
617  uint32_t status;
618 
619  //Interrupt service routine prologue
620  osEnterIsr();
621 
622  //This flag will be set if a higher priority task must be woken
623  flag = FALSE;
624 
625  //Clear system interrupt status
626  IntSystemStatusClear(SYS_INT_C0_RX);
627 
628  //Read the C0RXSTAT register to determine which channels caused the interrupt
629  status = EMAC_CTRL_C0RXSTAT_R;
630 
631  //Packet received on channel 0?
632  if(status & (1 << EMAC_CH0))
633  {
634  //Disable RX interrupts
636 
637  //Set event flag
638  nicDriverInterface->nicEvent = TRUE;
639  //Notify the TCP/IP stack of the event
640  flag |= osSetEventFromIsr(&netEvent);
641  }
642 
643  //Write the DMA end of interrupt vector
645 
646  //Interrupt service routine epilogue
647  osExitIsr(flag);
648 }
649 
650 
651 /**
652  * @brief OMAP-L138 Ethernet MAC event handler
653  * @param[in] interface Underlying network interface
654  **/
655 
657 {
658  error_t error;
659 
660  //Process all pending packets
661  do
662  {
663  //Read incoming packet
664  error = omapl138EthReceivePacket(interface);
665 
666  //No more data in the receive buffer?
667  } while(error != ERROR_BUFFER_EMPTY);
668 
669  //Re-enable RX interrupts
671 }
672 
673 
674 /**
675  * @brief Send a packet
676  * @param[in] interface Underlying network interface
677  * @param[in] buffer Multi-part buffer containing the data to send
678  * @param[in] offset Offset to the first data byte
679  * @param[in] ancillary Additional options passed to the stack along with
680  * the packet
681  * @return Error code
682  **/
683 
685  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
686 {
687  size_t length;
688  uint32_t temp;
689 
690  //Retrieve the length of the packet
691  length = netBufferGetLength(buffer) - offset;
692 
693  //Check the frame length
695  {
696  //The transmitter can accept another packet
697  osSetEvent(&interface->nicTxEvent);
698  //Report an error
699  return ERROR_INVALID_LENGTH;
700  }
701 
702  //Make sure the current buffer is available for writing
703  if((txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER) != 0)
704  {
705  return ERROR_FAILURE;
706  }
707 
708  //Mark the end of the queue with a NULL pointer
709  txCurBufferDesc->word0 = (uint32_t) NULL;
710 
711  //Copy user data to the transmit buffer
712  netBufferRead((uint8_t *) txCurBufferDesc->word1, buffer, offset, length);
713 
714  //Set the length of the buffer
715  txCurBufferDesc->word2 = length & EMAC_TX_WORD2_BUFFER_LENGTH;
716 
717  //Give the ownership of the descriptor to the DMA
718  txCurBufferDesc->word3 = EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
720 
721  //Link the current descriptor to the previous descriptor
722  txCurBufferDesc->prev->word0 = (uint32_t) txCurBufferDesc;
723 
724  //Read the status flags of the previous descriptor
725  temp = txCurBufferDesc->prev->word3 & (EMAC_TX_WORD3_SOP |
727 
728  //Misqueued buffer condition?
730  {
731  //Clear the misqueued buffer condition
732  txCurBufferDesc->prev->word3 = 0;
733 
734  //The host corrects the misqueued buffer condition by writing the
735  //misqueued packet’s buffer descriptor address to the appropriate
736  //TX DMA head descriptor pointer
737  EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) txCurBufferDesc;
738  }
739 
740  //Point to the next descriptor in the list
741  txCurBufferDesc = txCurBufferDesc->next;
742 
743  //Check whether the next buffer is available for writing
744  if((txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER) == 0)
745  {
746  //The transmitter can accept another packet
747  osSetEvent(&interface->nicTxEvent);
748  }
749 
750  //Data successfully written
751  return NO_ERROR;
752 }
753 
754 
755 /**
756  * @brief Receive a packet
757  * @param[in] interface Underlying network interface
758  * @return Error code
759  **/
760 
762 {
763  static uint32_t buffer[OMAPL138_ETH_RX_BUFFER_SIZE / 4];
764  error_t error;
765  size_t n;
766  uint32_t temp;
767 
768  //Current buffer available for reading?
769  if((rxCurBufferDesc->word3 & EMAC_RX_WORD3_OWNER) == 0)
770  {
771  //SOP and EOP flags should be set
772  if((rxCurBufferDesc->word3 & EMAC_RX_WORD3_SOP) != 0 &&
773  (rxCurBufferDesc->word3 & EMAC_RX_WORD3_EOP) != 0)
774  {
775  //Make sure no error occurred
776  if((rxCurBufferDesc->word3 & EMAC_RX_WORD3_ERROR_MASK) == 0)
777  {
778  //Retrieve the length of the frame
779  n = rxCurBufferDesc->word3 & EMAC_RX_WORD3_PACKET_LENGTH;
780  //Limit the number of data to read
782 
783  //Copy data from the receive buffer
784  osMemcpy(buffer, (uint8_t *) rxCurBufferDesc->word1, n);
785 
786  //Valid packet received
787  error = NO_ERROR;
788  }
789  else
790  {
791  //The received packet contains an error
792  error = ERROR_INVALID_PACKET;
793  }
794  }
795  else
796  {
797  //The packet is not valid
798  error = ERROR_INVALID_PACKET;
799  }
800 
801  //Mark the end of the queue with a NULL pointer
802  rxCurBufferDesc->word0 = (uint32_t) NULL;
803  //Restore the length of the buffer
804  rxCurBufferDesc->word2 = OMAPL138_ETH_RX_BUFFER_SIZE;
805  //Give the ownership of the descriptor back to the DMA
806  rxCurBufferDesc->word3 = EMAC_RX_WORD3_OWNER;
807 
808  //Link the current descriptor to the previous descriptor
809  rxCurBufferDesc->prev->word0 = (uint32_t) rxCurBufferDesc;
810 
811  //Read the status flags of the previous descriptor
812  temp = rxCurBufferDesc->prev->word3 & (EMAC_RX_WORD3_SOP |
814 
815  //Misqueued buffer condition?
817  {
818  //The host acts on the misqueued buffer condition by writing the added
819  //buffer descriptor address to the appropriate RX DMA head descriptor
820  //pointer
821  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
822  }
823 
824  //Write the RX completion pointer
825  EMAC_RXCP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
826 
827  //Point to the next descriptor in the list
828  rxCurBufferDesc = rxCurBufferDesc->next;
829  }
830  else
831  {
832  //No more data in the receive buffer
833  error = ERROR_BUFFER_EMPTY;
834  }
835 
836  //Check whether a valid packet has been received
837  if(!error)
838  {
839  NetRxAncillary ancillary;
840 
841  //Additional options can be passed to the stack along with the packet
842  ancillary = NET_DEFAULT_RX_ANCILLARY;
843 
844  //Pass the packet to the upper layer
845  nicProcessPacket(interface, (uint8_t *) buffer, n, &ancillary);
846  }
847 
848  //Return status code
849  return error;
850 }
851 
852 
853 /**
854  * @brief Configure MAC address filtering
855  * @param[in] interface Underlying network interface
856  * @return Error code
857  **/
858 
860 {
861  uint_t i;
862  uint_t k;
863  uint8_t *p;
864  uint32_t hashTable[2];
865  MacFilterEntry *entry;
866 
867  //Debug message
868  TRACE_DEBUG("Updating MAC filter...\r\n");
869 
870  //Clear hash table
871  hashTable[0] = 0;
872  hashTable[1] = 0;
873 
874  //The MAC address filter contains the list of MAC addresses to accept
875  //when receiving an Ethernet frame
876  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
877  {
878  //Point to the current entry
879  entry = &interface->macAddrFilter[i];
880 
881  //Valid entry?
882  if(entry->refCount > 0)
883  {
884  //Point to the MAC address
885  p = entry->addr.b;
886 
887  //Apply the hash function
888  k = (p[0] >> 2) ^ (p[0] << 4);
889  k ^= (p[1] >> 4) ^ (p[1] << 2);
890  k ^= (p[2] >> 6) ^ p[2];
891  k ^= (p[3] >> 2) ^ (p[3] << 4);
892  k ^= (p[4] >> 4) ^ (p[4] << 2);
893  k ^= (p[5] >> 6) ^ p[5];
894 
895  //The hash value is reduced to a 6-bit index
896  k &= 0x3F;
897 
898  //Update hash table contents
899  hashTable[k / 32] |= (1 << (k % 32));
900  }
901  }
902 
903  //Write the hash table
904  EMAC_MACHASH1_R = hashTable[0];
905  EMAC_MACHASH2_R = hashTable[1];
906 
907  //Debug message
908  TRACE_DEBUG(" MACHASH1 = %08" PRIX32 "\r\n", EMAC_MACHASH1_R);
909  TRACE_DEBUG(" MACHASH2 = %08" PRIX32 "\r\n", EMAC_MACHASH2_R);
910 
911  //Successful processing
912  return NO_ERROR;
913 }
914 
915 
916 /**
917  * @brief Adjust MAC configuration parameters for proper operation
918  * @param[in] interface Underlying network interface
919  * @return Error code
920  **/
921 
923 {
924  uint32_t config;
925 
926  //Read MAC control register
927  config = EMAC_MACCONTROL_R;
928 
929  //100BASE-TX or 10BASE-T operation mode?
930  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
931  {
932  config |= EMAC_MACCONTROL_RMIISPEED;
933  }
934  else
935  {
936  config &= ~EMAC_MACCONTROL_RMIISPEED;
937  }
938 
939  //Half-duplex or full-duplex mode?
940  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
941  {
942  config |= EMAC_MACCONTROL_FULLDUPLEX;
943  }
944  else
945  {
946  config &= ~EMAC_MACCONTROL_FULLDUPLEX;
947  }
948 
949  //Update MAC control register
950  EMAC_MACCONTROL_R = config;
951 
952  //Successful processing
953  return NO_ERROR;
954 }
955 
956 
957 /**
958  * @brief Write PHY register
959  * @param[in] opcode Access type (2 bits)
960  * @param[in] phyAddr PHY address (5 bits)
961  * @param[in] regAddr Register address (5 bits)
962  * @param[in] data Register value
963  **/
964 
965 void omapl138EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
966  uint8_t regAddr, uint16_t data)
967 {
968  uint32_t temp;
969 
970  //Valid opcode?
971  if(opcode == SMI_OPCODE_WRITE)
972  {
973  //Set up a write operation
974  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE;
975  //PHY address
976  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
977  //Register address
978  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
979  //Register value
980  temp |= data & MDIO_USERACCESS0_DATA;
981 
982  //Start a write operation
983  MDIO_USERACCESS0_R = temp;
984  //Wait for the write to complete
985  while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
986  {
987  }
988  }
989  else
990  {
991  //The MAC peripheral only supports standard Clause 22 opcodes
992  }
993 }
994 
995 
996 /**
997  * @brief Read PHY register
998  * @param[in] opcode Access type (2 bits)
999  * @param[in] phyAddr PHY address (5 bits)
1000  * @param[in] regAddr Register address (5 bits)
1001  * @return Register value
1002  **/
1003 
1004 uint16_t omapl138EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1005  uint8_t regAddr)
1006 {
1007  uint16_t data;
1008  uint32_t temp;
1009 
1010  //Valid opcode?
1011  if(opcode == SMI_OPCODE_READ)
1012  {
1013  //Set up a read operation
1014  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_READ;
1015  //PHY address
1016  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
1017  //Register address
1018  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
1019 
1020  //Start a read operation
1021  MDIO_USERACCESS0_R = temp;
1022  //Wait for the read to complete
1023  while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
1024  {
1025  }
1026 
1027  //Get register value
1028  data = MDIO_USERACCESS0_R & MDIO_USERACCESS0_DATA;
1029  }
1030  else
1031  {
1032  //The MAC peripheral only supports standard Clause 22 opcodes
1033  data = 0;
1034  }
1035 
1036  //Return the value of the PHY register
1037  return data;
1038 }
#define rxBuffer
#define txBuffer
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
#define SMI_OPCODE_WRITE
Definition: nic.h:66
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
void omapl138EthTick(NetInterface *interface)
OMAP-L138 Ethernet MAC timer handler.
error_t omapl138EthInit(NetInterface *interface)
OMAP-L138 Ethernet MAC initialization.
void omapl138EthEnableIrq(NetInterface *interface)
Enable interrupts.
void omapl138EthEventHandler(NetInterface *interface)
OMAP-L138 Ethernet MAC event handler.
error_t omapl138EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void omapl138EthRxIrqHandler(void)
Ethernet MAC receive interrupt.
void omapl138EthTxIrqHandler(void)
Ethernet MAC transmit interrupt.
uint16_t omapl138EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void omapl138EthDisableIrq(NetInterface *interface)
Disable interrupts.
error_t omapl138EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t omapl138EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define MDIO_OUTPUT_CLK
void omapl138EthInitBufferDesc(NetInterface *interface)
Initialize buffer descriptor lists.
#define MDIO_INPUT_CLK
void omapl138EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
const NicDriver omapl138EthDriver
OMAP-L138 Ethernet MAC driver.
__weak_func void omapl138EthInitGpio(NetInterface *interface)
GPIO configuration.
error_t omapl138EthReceivePacket(NetInterface *interface)
Receive a packet.
OMAP-L138 Ethernet MAC driver.
#define EMAC_CTRL_C0RXSTAT_R
#define EMAC_TXCONTROL_R
#define OMAPL138_ETH_TX_IRQ_CHANNEL
#define EMAC_TX_WORD3_EOQ
#define EMAC_MACEOIVECTOR_C0TX
#define EMAC_RX_WORD3_SOP
#define EMAC_TX_WORD2_BUFFER_LENGTH
#define EMAC_RXCONTROL_R
#define OMAPL138_ETH_RAM_CPPI_SECTION
#define EMAC_RX_WORD3_PACKET_LENGTH
#define EMAC_RXMBPENABLE_R
#define EMAC_CH7
#define EMAC_RXHDP_R(n)
#define OMAPL138_ETH_RAM_SECTION
#define EMAC_RX_WORD3_OWNER
#define EMAC_TX_WORD3_OWNER
#define EMAC_RXINTMASKSET_R
#define OMAPL138_ETH_RX_IRQ_CHANNEL
#define MDIO_USERACCESS0_R
#define OMAPL138_ETH_RX_BUFFER_COUNT
#define MDIO_CONTROL_R
#define EMAC_TXHDP_R(n)
#define OMAPL138_ETH_TX_BUFFER_SIZE
#define EMAC_RXBUFFEROFFSET_R
#define EMAC_CH0
#define EMAC_CORE0
#define EMAC_SOFTRESET_R
#define EMAC_TXINTMASKSET_R
#define EMAC_RXUNICASTSET_R
#define EMAC_CTRL_CnRXEN_R(n)
#define EMAC_TX_WORD3_EOP
#define EMAC_RX_WORD3_ERROR_MASK
#define EMAC_CTRL_CnTXEN_R(n)
#define EMAC_MACHASH2_R
#define EMAC_TXINTMASKCLEAR_R
#define EMAC_RX_WORD3_EOP
#define OMAPL138_ETH_RX_BUFFER_SIZE
#define EMAC_MACSRCADDRHI_R
#define SYSCFG0_CFGCHIP3_R
#define EMAC_TX_WORD3_PACKET_LENGTH
#define EMAC_TXCP_R(n)
#define EMAC_MACEOIVECTOR_C0RX
#define EMAC_CTRL_C0TXSTAT_R
#define SYSCFG0_PINMUX_R(n)
#define EMAC_RXINTMASKCLEAR_R
#define EMAC_MACADDRLO_R
#define EMAC_MACINDEX_R
#define EMAC_CH1
#define EMAC_MACADDRHI_R
#define EMAC_MACHASH1_R
#define EMAC_RXUNICASTCLEAR_R
#define EMAC_RXCP_R(n)
#define EMAC_MACEOIVECTOR_R
#define EMAC_CTRL_SOFTRESET_R
#define EMAC_RX_WORD3_EOQ
#define EMAC_TX_WORD3_SOP
#define EMAC_MACSRCADDRLO_R
#define OMAPL138_ETH_TX_BUFFER_COUNT
#define EMAC_MACCONTROL_R
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
RX buffer descriptor.
struct _Omapl138RxBufferDesc * prev
struct _Omapl138RxBufferDesc * next
TX buffer descriptor.
struct _Omapl138TxBufferDesc * prev
struct _Omapl138TxBufferDesc * next
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368