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