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  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 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 1.9.6
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 = ".ram_no_cache"
63 //Receive buffer
64 #pragma data_alignment = 4
65 #pragma location = ".ram_no_cache"
67 //Transmit buffer descriptors
68 #pragma data_alignment = 4
69 #pragma location = ".ram_cppi"
71 //Receive buffer descriptors
72 #pragma data_alignment = 4
73 #pragma location = ".ram_cppi"
75 
76 //Keil MDK-ARM or GCC compiler?
77 #else
78 
79 //Transmit buffer
81  __attribute__((aligned(4), __section__(".ram_no_cache")));
82 //Receive buffer
84  __attribute__((aligned(4), __section__(".ram_no_cache")));
85 //Transmit buffer descriptors
87  __attribute__((aligned(4), __section__(".ram_cppi")));
88 //Receive buffer descriptors
90  __attribute__((aligned(4), __section__(".ram_cppi")));
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)
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)
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  //PHY transceiver initialization
172  error = interface->phyDriver->init(interface);
173  //Failed to initialize PHY transceiver?
174  if(error)
175  return error;
176 
177  //Clear the control registers
178  EMAC_MACCONTROL_R = 0;
179  EMAC_RXCONTROL_R = 0;
180  EMAC_TXCONTROL_R = 0;
181 
182  //Initialize all 16 header descriptor pointer registers to 0
183  for(channel = EMAC_CH0; channel <= EMAC_CH7; channel++)
184  {
185  //TX head descriptor pointer
186  EMAC_TXHDP_R(channel) = 0;
187  //TX completion pointer
188  EMAC_TXCP_R(channel) = 0;
189  //RX head descriptor pointer
190  EMAC_RXHDP_R(channel) = 0;
191  //RX completion pointer
192  EMAC_RXCP_R(channel) = 0;
193  }
194 
195  //Set the upper 32 bits of the source MAC address
196  EMAC_MACSRCADDRHI_R = interface->macAddr.b[0] |
197  (interface->macAddr.b[1] << 8) |
198  (interface->macAddr.b[2] << 16) |
199  (interface->macAddr.b[3] << 24);
200 
201  //Set the lower 16 bits of the source MAC address
202  EMAC_MACSRCADDRLO_R = interface->macAddr.b[4] |
203  (interface->macAddr.b[5] << 8);
204 
205  //Write the channel number to the MAC index register
207 
208  //Set the upper 32 bits of the destination MAC address
209  EMAC_MACADDRHI_R = interface->macAddr.b[0] |
210  (interface->macAddr.b[1] << 8) |
211  (interface->macAddr.b[2] << 16) |
212  (interface->macAddr.b[3] << 24);
213 
214  //Set the lower 16 bits of the destination MAC address
215  temp = interface->macAddr.b[4] |
216  (interface->macAddr.b[5] << 8);
217 
218  //Use the current MAC address to match incoming packet addresses
219  EMAC_MACADDRLO_R = EMAC_MACADDRLO_VALID | EMAC_MACADDRLO_MATCHFILT |
220  (EMAC_CH0 << EMAC_MACADDRLO_CHANNEL_SHIFT) | temp;
221 
222  //Be sure to program all eight MAC address registers, whether the
223  //receive channel is to be enabled or not
224  for(channel = EMAC_CH1; channel <= EMAC_CH7; channel++)
225  {
226  //Write the channel number to the MAC index register
227  EMAC_MACINDEX_R = channel;
228  //The MAC address is not valid
229  EMAC_MACADDRLO_R = (channel << EMAC_MACADDRLO_CHANNEL_SHIFT);
230  }
231 
232  //Clear the MAC address hash registers
233  EMAC_MACHASH1_R = 0;
234  EMAC_MACHASH2_R = 0;
235 
236  //The RX buffer offset must be initialized to zero
238 
239  //Clear all unicast channels
240  EMAC_RXUNICASTCLEAR_R = 0xFF;
241 
242  //Accept unicast frames
243  EMAC_RXUNICASTSET_R |= (1 << EMAC_CH0);
244 
245  //Received CRC is transferred to memory for all channels
246  EMAC_RXMBPENABLE_R = EMAC_RXMBPENABLE_RXPASSCRC;
247 
248  //Accept broadcast frames
249  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXBROADEN |
250  (EMAC_CH0 << EMAC_RXMBPENABLE_RXBROADCH_SHIFT);
251 
252  //Accept hash matching multicast frames
253  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXMULTEN |
254  (EMAC_CH0 << EMAC_RXMBPENABLE_RXMULTCH_SHIFT);
255 
256  //Register interrupt handlers
257  IntRegister(SYS_INT_C0_TX, omapl138EthTxIrqHandler);
258  IntRegister(SYS_INT_C0_RX, omapl138EthRxIrqHandler);
259 
260  //Set the channel number for the TX interrupt
261  IntChannelSet(SYS_INT_C0_TX, OMAPL138_ETH_TX_IRQ_CHANNEL);
262  //Set the channel number for the RX interrupt
263  IntChannelSet(SYS_INT_C0_RX, OMAPL138_ETH_RX_IRQ_CHANNEL);
264 
265  //Clear all unused channel interrupt bits
266  EMAC_TXINTMASKCLEAR_R = 0xFF;
267  EMAC_RXINTMASKCLEAR_R = 0xFF;
268 
269  //Enable the receive and transmit channel interrupt bits
270  EMAC_TXINTMASKSET_R = (1 << EMAC_CH0);
271  EMAC_RXINTMASKSET_R = (1 << EMAC_CH0);
272 
273  //Configure TX and RX buffer descriptors
274  omapl138EthInitBufferDesc(interface);
275 
276  //Write the RX DMA head descriptor pointer
277  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
278 
279  //Enable the receive and transmit DMA controllers
280  EMAC_TXCONTROL_R = EMAC_TXCONTROL_TXEN;
281  EMAC_RXCONTROL_R = EMAC_RXCONTROL_RXEN;
282 
283  //Enable TX and RX
284  EMAC_MACCONTROL_R = EMAC_MACCONTROL_GMIIEN;
285 
286  //Enable TX and RX completion interrupts
289 
290  //Accept any packets from the upper layer
291  osSetEvent(&interface->nicTxEvent);
292 
293  //Successful initialization
294  return NO_ERROR;
295 }
296 
297 
298 //TMDSLCDK138 board?
299 #if defined(USE_TMDSLCDK138)
300 
301 /**
302  * @brief GPIO configuration
303  * @param[in] interface Underlying network interface
304  **/
305 
306 void omapl138EthInitGpio(NetInterface *interface)
307 {
308  uint32_t temp;
309 
310  //Enable GPIO module
311  PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_GPIO,
312  PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
313 
314  //Configure MII_TXD0, MII_TXD1, MII_TXD2, MII_TXD3, MII_COL, MII_TXCLK and MII_TXEN
315  temp = SYSCFG0_PINMUX_R(2) & ~(SYSCFG_PINMUX2_PINMUX2_31_28 |
316  SYSCFG_PINMUX2_PINMUX2_27_24 | SYSCFG_PINMUX2_PINMUX2_23_20 |
317  SYSCFG_PINMUX2_PINMUX2_19_16 | SYSCFG_PINMUX2_PINMUX2_15_12 |
318  SYSCFG_PINMUX2_PINMUX2_11_8 | SYSCFG_PINMUX2_PINMUX2_7_4);
319 
320  SYSCFG0_PINMUX_R(2) = temp |
321  (SYSCFG_PINMUX2_PINMUX2_31_28_MII_TXD0 << SYSCFG_PINMUX2_PINMUX2_31_28_SHIFT) |
322  (SYSCFG_PINMUX2_PINMUX2_27_24_MII_TXD1 << SYSCFG_PINMUX2_PINMUX2_27_24_SHIFT) |
323  (SYSCFG_PINMUX2_PINMUX2_23_20_MII_TXD2 << SYSCFG_PINMUX2_PINMUX2_23_20_SHIFT) |
324  (SYSCFG_PINMUX2_PINMUX2_19_16_MII_TXD3 << SYSCFG_PINMUX2_PINMUX2_19_16_SHIFT) |
325  (SYSCFG_PINMUX2_PINMUX2_15_12_MII_COL << SYSCFG_PINMUX2_PINMUX2_15_12_SHIFT) |
326  (SYSCFG_PINMUX2_PINMUX2_11_8_MII_TXCLK << SYSCFG_PINMUX2_PINMUX2_11_8_SHIFT) |
327  (SYSCFG_PINMUX2_PINMUX2_7_4_MII_TXEN << SYSCFG_PINMUX2_PINMUX2_7_4_SHIFT);
328 
329  //Configure MII_RXD0, MII_RXD1, MII_RXD2, MII_RXD3, MII_CRS, MII_RXER, MII_RXDV and RXCLK
330  temp = SYSCFG0_PINMUX_R(3) & ~(SYSCFG_PINMUX3_PINMUX3_31_28 |
331  SYSCFG_PINMUX3_PINMUX3_27_24 | SYSCFG_PINMUX3_PINMUX3_23_20 |
332  SYSCFG_PINMUX3_PINMUX3_19_16 | SYSCFG_PINMUX3_PINMUX3_15_12 |
333  SYSCFG_PINMUX3_PINMUX3_11_8 | SYSCFG_PINMUX3_PINMUX3_7_4 |
334  SYSCFG_PINMUX3_PINMUX3_3_0);
335 
336  SYSCFG0_PINMUX_R(3) = temp |
337  (SYSCFG_PINMUX3_PINMUX3_31_28_MII_RXD0 << SYSCFG_PINMUX3_PINMUX3_31_28_SHIFT) |
338  (SYSCFG_PINMUX3_PINMUX3_27_24_MII_RXD1 << SYSCFG_PINMUX3_PINMUX3_27_24_SHIFT) |
339  (SYSCFG_PINMUX3_PINMUX3_23_20_MII_RXD2 << SYSCFG_PINMUX3_PINMUX3_23_20_SHIFT) |
340  (SYSCFG_PINMUX3_PINMUX3_19_16_MII_RXD3 << SYSCFG_PINMUX3_PINMUX3_19_16_SHIFT) |
341  (SYSCFG_PINMUX3_PINMUX3_15_12_MII_CRS << SYSCFG_PINMUX3_PINMUX3_15_12_SHIFT) |
342  (SYSCFG_PINMUX3_PINMUX3_11_8_MII_RXER << SYSCFG_PINMUX3_PINMUX3_11_8_SHIFT) |
343  (SYSCFG_PINMUX3_PINMUX3_7_4_MII_RXDV << SYSCFG_PINMUX3_PINMUX3_7_4_SHIFT) |
344  (SYSCFG_PINMUX3_PINMUX3_3_0_MII_RXCLK << SYSCFG_PINMUX3_PINMUX3_3_0_SHIFT);
345 
346  //Configure MDIO and MDCLK
347  temp = SYSCFG0_PINMUX_R(4) & ~(SYSCFG_PINMUX4_PINMUX4_3_0 |
348  SYSCFG_PINMUX4_PINMUX4_7_4);
349 
350  SYSCFG0_PINMUX_R(4) = temp |
351  (SYSCFG_PINMUX4_PINMUX4_7_4_MDIO_D << SYSCFG_PINMUX4_PINMUX4_7_4_SHIFT) |
352  (SYSCFG_PINMUX4_PINMUX4_3_0_MDIO_CLK << SYSCFG_PINMUX4_PINMUX4_3_0_SHIFT);
353 
354  //Select MII interface mode
355  SYSCFG0_CFGCHIP3_R &= ~SYSCFG_CFGCHIP3_RMII_SEL;
356 }
357 
358 #endif
359 
360 
361 /**
362  * @brief Initialize buffer descriptor lists
363  * @param[in] interface Underlying network interface
364  **/
365 
367 {
368  uint_t i;
369  uint_t nextIndex;
370  uint_t prevIndex;
371 
372  //Initialize TX buffer descriptor list
373  for(i = 0; i < OMAPL138_ETH_TX_BUFFER_COUNT; i++)
374  {
375  //Index of the next buffer
376  nextIndex = (i + 1) % OMAPL138_ETH_TX_BUFFER_COUNT;
377  //Index of the previous buffer
379 
380  //Next descriptor pointer
381  txBufferDesc[i].word0 = (uint32_t) NULL;
382  //Buffer pointer
383  txBufferDesc[i].word1 = (uint32_t) txBuffer[i];
384  //Buffer offset and buffer length
385  txBufferDesc[i].word2 = 0;
386  //Status flags and packet length
387  txBufferDesc[i].word3 = 0;
388 
389  //Form a doubly linked list
390  txBufferDesc[i].next = &txBufferDesc[nextIndex];
391  txBufferDesc[i].prev = &txBufferDesc[prevIndex];
392  }
393 
394  //Point to the very first descriptor
395  txCurBufferDesc = &txBufferDesc[0];
396 
397  //Mark the end of the queue
398  txCurBufferDesc->prev->word3 = EMAC_TX_WORD3_SOP |
400 
401  //Initialize RX buffer descriptor list
402  for(i = 0; i < OMAPL138_ETH_RX_BUFFER_COUNT; i++)
403  {
404  //Index of the next buffer
405  nextIndex = (i + 1) % OMAPL138_ETH_RX_BUFFER_COUNT;
406  //Index of the previous buffer
408 
409  //Next descriptor pointer
410  rxBufferDesc[i].word0 = (uint32_t) &rxBufferDesc[nextIndex];
411  //Buffer pointer
412  rxBufferDesc[i].word1 = (uint32_t) rxBuffer[i];
413  //Buffer offset and buffer length
414  rxBufferDesc[i].word2 = OMAPL138_ETH_RX_BUFFER_SIZE;
415  //Status flags and packet length
416  rxBufferDesc[i].word3 = EMAC_RX_WORD3_OWNER;
417 
418  //Form a doubly linked list
419  rxBufferDesc[i].next = &rxBufferDesc[nextIndex];
420  rxBufferDesc[i].prev = &rxBufferDesc[prevIndex];
421  }
422 
423  //Point to the very first descriptor
424  rxCurBufferDesc = &rxBufferDesc[0];
425 
426  //Mark the end of the queue
427  rxCurBufferDesc->prev->word0 = (uint32_t) NULL;
428 }
429 
430 
431 /**
432  * @brief OMAP-L138 Ethernet MAC timer handler
433  *
434  * This routine is periodically called by the TCP/IP stack to
435  * handle periodic operations such as polling the link state
436  *
437  * @param[in] interface Underlying network interface
438  **/
439 
441 {
442  //Handle periodic operations
443  interface->phyDriver->tick(interface);
444 
445  //Misqueued buffer condition?
446  if(rxCurBufferDesc->word3 & EMAC_RX_WORD3_OWNER)
447  {
448  if(EMAC_RXHDP_R(EMAC_CH0) == 0)
449  {
450  //The host acts on the misqueued buffer condition by writing the added
451  //buffer descriptor address to the appropriate RX DMA head descriptor
452  //pointer
453  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
454  }
455  }
456 }
457 
458 
459 /**
460  * @brief Enable interrupts
461  * @param[in] interface Underlying network interface
462  **/
463 
465 {
466  //Enable Ethernet MAC interrupts
467  IntSystemEnable(SYS_INT_C0_TX);
468  IntSystemEnable(SYS_INT_C0_RX);
469 
470  //Enable Ethernet PHY interrupts
471  interface->phyDriver->enableIrq(interface);
472 }
473 
474 
475 /**
476  * @brief Disable interrupts
477  * @param[in] interface Underlying network interface
478  **/
479 
481 {
482  //Disable Ethernet MAC interrupts
483  IntSystemDisable(SYS_INT_C0_TX);
484  IntSystemDisable(SYS_INT_C0_RX);
485 
486  //Disable Ethernet PHY interrupts
487  interface->phyDriver->disableIrq(interface);
488 }
489 
490 
491 /**
492  * @brief Ethernet MAC transmit interrupt
493  **/
494 
496 {
497  bool_t flag;
498  uint32_t status;
499  uint32_t temp;
501 
502  //Interrupt service routine prologue
503  osEnterIsr();
504 
505  //This flag will be set if a higher priority task must be woken
506  flag = FALSE;
507 
508  //Clear system interrupt status
509  IntSystemStatusClear(SYS_INT_C0_TX);
510 
511  //Read the C0TXSTAT register to determine which channels caused the interrupt
512  status = EMAC_CTRL_C0TXSTAT_R;
513 
514  //Packet transmitted on channel 0?
515  if(status & (1 << EMAC_CH0))
516  {
517  //Point to the buffer descriptor
519 
520  //Read the status flags
521  temp = p->word3 & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
523 
524  //Misqueued buffer condition?
526  {
527  //Check whether the next descriptor pointer is non-zero
528  if(p->word0 != 0)
529  {
530  //The host corrects the misqueued buffer condition by writing the
531  //misqueued packetís buffer descriptor address to the appropriate
532  //TX DMA head descriptor pointer
533  EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) p->word0;
534  }
535  }
536 
537  //Write the TX completion pointer
538  EMAC_TXCP_R(EMAC_CH0) = (uint32_t) p;
539 
540  //Check whether the TX buffer is available for writing
541  if(!(txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER))
542  {
543  //Notify the TCP/IP stack that the transmitter is ready to send
544  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
545  }
546  }
547 
548  //Write the DMA end of interrupt vector
550 
551  //Interrupt service routine epilogue
552  osExitIsr(flag);
553 }
554 
555 
556 /**
557  * @brief Ethernet MAC receive interrupt
558  **/
559 
561 {
562  bool_t flag;
563  uint32_t status;
564 
565  //Interrupt service routine prologue
566  osEnterIsr();
567 
568  //This flag will be set if a higher priority task must be woken
569  flag = FALSE;
570 
571  //Clear system interrupt status
572  IntSystemStatusClear(SYS_INT_C0_RX);
573 
574  //Read the C0RXSTAT register to determine which channels caused the interrupt
575  status = EMAC_CTRL_C0RXSTAT_R;
576 
577  //Packet received on channel 0?
578  if(status & (1 << EMAC_CH0))
579  {
580  //Disable RX interrupts
582 
583  //Set event flag
584  nicDriverInterface->nicEvent = TRUE;
585  //Notify the TCP/IP stack of the event
586  flag |= osSetEventFromIsr(&netEvent);
587  }
588 
589  //Write the DMA end of interrupt vector
591 
592  //Interrupt service routine epilogue
593  osExitIsr(flag);
594 }
595 
596 
597 /**
598  * @brief OMAP-L138 Ethernet MAC event handler
599  * @param[in] interface Underlying network interface
600  **/
601 
603 {
604  error_t error;
605 
606  //Process all pending packets
607  do
608  {
609  //Read incoming packet
610  error = omapl138EthReceivePacket(interface);
611 
612  //No more data in the receive buffer?
613  } while(error != ERROR_BUFFER_EMPTY);
614 
615  //Re-enable RX interrupts
617 }
618 
619 
620 /**
621  * @brief Send a packet
622  * @param[in] interface Underlying network interface
623  * @param[in] buffer Multi-part buffer containing the data to send
624  * @param[in] offset Offset to the first data byte
625  * @return Error code
626  **/
627 
629  const NetBuffer *buffer, size_t offset)
630 {
631  size_t length;
632  uint32_t temp;
633 
634  //Retrieve the length of the packet
635  length = netBufferGetLength(buffer) - offset;
636 
637  //Check the frame length
639  {
640  //The transmitter can accept another packet
641  osSetEvent(&interface->nicTxEvent);
642  //Report an error
643  return ERROR_INVALID_LENGTH;
644  }
645 
646  //Make sure the current buffer is available for writing
647  if(txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER)
648  return ERROR_FAILURE;
649 
650  //Mark the end of the queue with a NULL pointer
651  txCurBufferDesc->word0 = (uint32_t) NULL;
652 
653  //Copy user data to the transmit buffer
654  netBufferRead((uint8_t *) txCurBufferDesc->word1, buffer, offset, length);
655 
656  //Set the length of the buffer
657  txCurBufferDesc->word2 = length & EMAC_TX_WORD2_BUFFER_LENGTH;
658 
659  //Give the ownership of the descriptor to the DMA
660  txCurBufferDesc->word3 = EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
662 
663  //Link the current descriptor to the previous descriptor
664  txCurBufferDesc->prev->word0 = (uint32_t) txCurBufferDesc;
665 
666  //Read the status flags of the previous descriptor
667  temp = txCurBufferDesc->prev->word3 & (EMAC_TX_WORD3_SOP |
669 
670  //Misqueued buffer condition?
672  {
673  //Clear the misqueued buffer condition
674  txCurBufferDesc->prev->word3 = 0;
675 
676  //The host corrects the misqueued buffer condition by writing the
677  //misqueued packetís buffer descriptor address to the appropriate
678  //TX DMA head descriptor pointer
679  EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) txCurBufferDesc;
680  }
681 
682  //Point to the next descriptor in the list
683  txCurBufferDesc = txCurBufferDesc->next;
684 
685  //Check whether the next buffer is available for writing
686  if(!(txCurBufferDesc->word3 & EMAC_TX_WORD3_OWNER))
687  {
688  //The transmitter can accept another packet
689  osSetEvent(&interface->nicTxEvent);
690  }
691 
692  //Data successfully written
693  return NO_ERROR;
694 }
695 
696 
697 /**
698  * @brief Receive a packet
699  * @param[in] interface Underlying network interface
700  * @return Error code
701  **/
702 
704 {
705  static uint8_t buffer[OMAPL138_ETH_RX_BUFFER_SIZE];
706  error_t error;
707  size_t n;
708  uint32_t temp;
709 
710  //The current buffer is available for reading?
711  if(!(rxCurBufferDesc->word3 & EMAC_RX_WORD3_OWNER))
712  {
713  //SOP and EOP flags should be set
714  if((rxCurBufferDesc->word3 & EMAC_RX_WORD3_SOP) &&
715  (rxCurBufferDesc->word3 & EMAC_RX_WORD3_EOP))
716  {
717  //Make sure no error occurred
718  if(!(rxCurBufferDesc->word3 & EMAC_RX_WORD3_ERROR_MASK))
719  {
720  //Retrieve the length of the frame
721  n = rxCurBufferDesc->word3 & EMAC_RX_WORD3_PACKET_LENGTH;
722  //Limit the number of data to read
724 
725  //Copy data from the receive buffer
726  memcpy(buffer, (uint8_t *) rxCurBufferDesc->word1, n);
727 
728  //Valid packet received
729  error = NO_ERROR;
730  }
731  else
732  {
733  //The received packet contains an error
734  error = ERROR_INVALID_PACKET;
735  }
736  }
737  else
738  {
739  //The packet is not valid
740  error = ERROR_INVALID_PACKET;
741  }
742 
743  //Mark the end of the queue with a NULL pointer
744  rxCurBufferDesc->word0 = (uint32_t) NULL;
745  //Restore the length of the buffer
746  rxCurBufferDesc->word2 = OMAPL138_ETH_RX_BUFFER_SIZE;
747  //Give the ownership of the descriptor back to the DMA
748  rxCurBufferDesc->word3 = EMAC_RX_WORD3_OWNER;
749 
750  //Link the current descriptor to the previous descriptor
751  rxCurBufferDesc->prev->word0 = (uint32_t) rxCurBufferDesc;
752 
753  //Read the status flags of the previous descriptor
754  temp = rxCurBufferDesc->prev->word3 & (EMAC_RX_WORD3_SOP |
756 
757  //Misqueued buffer condition?
759  {
760  //The host acts on the misqueued buffer condition by writing the added
761  //buffer descriptor address to the appropriate RX DMA head descriptor
762  //pointer
763  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
764  }
765 
766  //Write the RX completion pointer
767  EMAC_RXCP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
768 
769  //Point to the next descriptor in the list
770  rxCurBufferDesc = rxCurBufferDesc->next;
771  }
772  else
773  {
774  //No more data in the receive buffer
775  error = ERROR_BUFFER_EMPTY;
776  }
777 
778  //Check whether a valid packet has been received
779  if(!error)
780  {
781  //Pass the packet to the upper layer
782  nicProcessPacket(interface, buffer, n);
783  }
784 
785  //Return status code
786  return error;
787 }
788 
789 
790 /**
791  * @brief Configure MAC address filtering
792  * @param[in] interface Underlying network interface
793  * @return Error code
794  **/
795 
797 {
798  uint_t i;
799  uint_t k;
800  uint8_t *p;
801  uint32_t hashTable[2];
802  MacFilterEntry *entry;
803 
804  //Debug message
805  TRACE_DEBUG("Updating MAC filter...\r\n");
806 
807  //Clear hash table
808  hashTable[0] = 0;
809  hashTable[1] = 0;
810 
811  //The MAC address filter contains the list of MAC addresses to accept
812  //when receiving an Ethernet frame
813  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
814  {
815  //Point to the current entry
816  entry = &interface->macAddrFilter[i];
817 
818  //Valid entry?
819  if(entry->refCount > 0)
820  {
821  //Point to the MAC address
822  p = entry->addr.b;
823 
824  //Apply the hash function
825  k = (p[0] >> 2) ^ (p[0] << 4);
826  k ^= (p[1] >> 4) ^ (p[1] << 2);
827  k ^= (p[2] >> 6) ^ p[2];
828  k ^= (p[3] >> 2) ^ (p[3] << 4);
829  k ^= (p[4] >> 4) ^ (p[4] << 2);
830  k ^= (p[5] >> 6) ^ p[5];
831 
832  //The hash value is reduced to a 6-bit index
833  k &= 0x3F;
834 
835  //Update hash table contents
836  hashTable[k / 32] |= (1 << (k % 32));
837  }
838  }
839 
840  //Write the hash table
841  EMAC_MACHASH1_R = hashTable[0];
842  EMAC_MACHASH2_R = hashTable[1];
843 
844  //Debug message
845  TRACE_DEBUG(" MACHASH1 = %08" PRIX32 "\r\n", EMAC_MACHASH1_R);
846  TRACE_DEBUG(" MACHASH2 = %08" PRIX32 "\r\n", EMAC_MACHASH2_R);
847 
848  //Successful processing
849  return NO_ERROR;
850 }
851 
852 
853 /**
854  * @brief Adjust MAC configuration parameters for proper operation
855  * @param[in] interface Underlying network interface
856  * @return Error code
857  **/
858 
860 {
861  uint32_t config;
862 
863  //Read MAC control register
864  config = EMAC_MACCONTROL_R;
865 
866  //100BASE-TX or 10BASE-T operation mode?
867  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
868  config |= EMAC_MACCONTROL_RMIISPEED;
869  else
870  config &= ~EMAC_MACCONTROL_RMIISPEED;
871 
872  //Half-duplex or full-duplex mode?
873  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
874  config |= EMAC_MACCONTROL_FULLDUPLEX;
875  else
876  config &= ~EMAC_MACCONTROL_FULLDUPLEX;
877 
878  //Update MAC control register
879  EMAC_MACCONTROL_R = config;
880 
881  //Successful processing
882  return NO_ERROR;
883 }
884 
885 
886 /**
887  * @brief Write PHY register
888  * @param[in] opcode Access type (2 bits)
889  * @param[in] phyAddr PHY address (5 bits)
890  * @param[in] regAddr Register address (5 bits)
891  * @param[in] data Register value
892  **/
893 
894 void omapl138EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
895  uint8_t regAddr, uint16_t data)
896 {
897  uint32_t temp;
898 
899  //Valid opcode?
900  if(opcode == SMI_OPCODE_WRITE)
901  {
902  //Set up a write operation
903  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE;
904  //PHY address
905  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
906  //Register address
907  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
908  //Register value
909  temp |= data & MDIO_USERACCESS0_DATA;
910 
911  //Start a write operation
912  MDIO_USERACCESS0_R = temp;
913  //Wait for the write to complete
914  while(MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO)
915  {
916  }
917  }
918  else
919  {
920  //The MAC peripheral only supports standard Clause 22 opcodes
921  }
922 }
923 
924 
925 /**
926  * @brief Read PHY register
927  * @param[in] opcode Access type (2 bits)
928  * @param[in] phyAddr PHY address (5 bits)
929  * @param[in] regAddr Register address (5 bits)
930  * @return Register value
931  **/
932 
933 uint16_t omapl138EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
934  uint8_t regAddr)
935 {
936  uint16_t data;
937  uint32_t temp;
938 
939  //Valid opcode?
940  if(opcode == SMI_OPCODE_READ)
941  {
942  //Set up a read operation
943  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_READ;
944  //PHY address
945  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
946  //Register address
947  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
948 
949  //Start a read operation
950  MDIO_USERACCESS0_R = temp;
951  //Wait for the read to complete
952  while(MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO)
953  {
954  }
955 
956  //Get register value
957  data = MDIO_USERACCESS0_R & MDIO_USERACCESS0_DATA;
958  }
959  else
960  {
961  //The MAC peripheral only supports standard Clause 22 opcodes
962  data = 0;
963  }
964 
965  //Return the value of the PHY register
966  return data;
967 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define EMAC_MACINDEX_R
#define EMAC_CORE0
uint8_t length
Definition: dtls_misc.h:149
uint8_t opcode
Definition: dns_common.h:172
#define EMAC_RXUNICASTCLEAR_R
#define MDIO_OUTPUT_CLK
RX buffer descriptor.
int bool_t
Definition: compiler_port.h:49
#define EMAC_MACCONTROL_R
void omapl138EthEnableIrq(NetInterface *interface)
Enable interrupts.
#define EMAC_MACADDRLO_R
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:672
uint16_t omapl138EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define EMAC_MACSRCADDRLO_R
#define OMAPL138_ETH_TX_IRQ_CHANNEL
uint8_t p
Definition: ndp.h:298
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:383
#define EMAC_TX_WORD3_EOQ
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define EMAC_MACHASH1_R
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:74
#define TRUE
Definition: os_port.h:50
#define EMAC_CTRL_C0RXSTAT_R
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:223
#define EMAC_MACSRCADDRHI_R
void omapl138EthInitBufferDesc(NetInterface *interface)
Initialize buffer descriptor lists.
#define EMAC_SOFTRESET_R
#define EMAC_RXCONTROL_R
#define SYSCFG0_PINMUX_R(n)
#define EMAC_MACHASH2_R
#define OMAPL138_ETH_RX_BUFFER_COUNT
#define osExitIsr(flag)
#define EMAC_MACEOIVECTOR_C0TX
OMAP-L138 Ethernet MAC controller.
#define SMI_OPCODE_WRITE
Definition: nic.h:62
#define OMAPL138_ETH_TX_BUFFER_SIZE
#define EMAC_TX_WORD3_EOP
#define MDIO_USERACCESS0_R
#define OMAPL138_ETH_TX_BUFFER_COUNT
void omapl138EthTick(NetInterface *interface)
OMAP-L138 Ethernet MAC timer handler.
#define FALSE
Definition: os_port.h:46
#define EMAC_RXBUFFEROFFSET_R
#define MDIO_CONTROL_R
void omapl138EthTxIrqHandler(void)
Ethernet MAC transmit interrupt.
error_t
Error codes.
Definition: error.h:42
#define EMAC_CTRL_SOFTRESET_R
#define EMAC_MACEOIVECTOR_R
#define SYSCFG0_CFGCHIP3_R
#define EMAC_RX_WORD3_PACKET_LENGTH
#define EMAC_TX_WORD3_PACKET_LENGTH
#define EMAC_CH7
Generic error code.
Definition: error.h:45
#define EMAC_CTRL_C0TXSTAT_R
#define EMAC_MACADDRHI_R
#define EMAC_RXINTMASKSET_R
#define EMAC_RX_WORD3_SOP
error_t omapl138EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
#define txBuffer
void omapl138EthDisableIrq(NetInterface *interface)
Disable interrupts.
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:222
#define EMAC_RXUNICASTSET_R
#define EMAC_RX_WORD3_ERROR_MASK
void omapl138EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void omapl138EthInitGpio(NetInterface *interface)
OsEvent netEvent
Definition: net.c:77
#define SMI_OPCODE_READ
Definition: nic.h:63
#define OMAPL138_ETH_RX_IRQ_CHANNEL
struct _Omapl138TxBufferDesc * prev
#define TRACE_INFO(...)
Definition: debug.h:94
error_t omapl138EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define EMAC_TXHDP_R(n)
#define EMAC_CH0
#define MIN(a, b)
Definition: os_port.h:62
#define EMAC_TX_WORD3_SOP
#define rxBuffer
#define OMAPL138_ETH_RX_BUFFER_SIZE
#define EMAC_TXCONTROL_R
#define EMAC_TX_WORD2_BUFFER_LENGTH
#define EMAC_CH1
#define EMAC_TXINTMASKCLEAR_R
void omapl138EthRxIrqHandler(void)
Ethernet MAC receive interrupt.
#define EMAC_CTRL_CnTXEN_R(n)
#define EMAC_RX_WORD3_EOQ
#define TRACE_DEBUG(...)
Definition: debug.h:106
#define EMAC_RXMBPENABLE_R
#define EMAC_MACEOIVECTOR_C0RX
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:91
uint8_t n
error_t omapl138EthReceivePacket(NetInterface *interface)
Receive a packet.
MAC filter table entry.
Definition: ethernet.h:220
#define EMAC_RXCP_R(n)
#define EMAC_TXINTMASKSET_R
void omapl138EthEventHandler(NetInterface *interface)
OMAP-L138 Ethernet MAC event handler.
#define osEnterIsr()
#define EMAC_CTRL_CnRXEN_R(n)
#define MDIO_INPUT_CLK
error_t omapl138EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
const NicDriver omapl138EthDriver
OMAP-L138 Ethernet MAC driver.
#define EMAC_TXCP_R(n)
#define EMAC_RXHDP_R(n)
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define EMAC_RX_WORD3_EOP
struct _Omapl138TxBufferDesc * next
error_t omapl138EthInit(NetInterface *interface)
OMAP-L138 Ethernet MAC initialization.
#define EMAC_TX_WORD3_OWNER
unsigned int uint_t
Definition: compiler_port.h:45
#define EMAC_RX_WORD3_OWNER
TCP/IP stack core.
uint8_t data[]
Definition: dtls_misc.h:176
struct _Omapl138RxBufferDesc * prev
NIC driver.
Definition: nic.h:179
struct _Omapl138RxBufferDesc * next
TX buffer descriptor.
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define EMAC_RXINTMASKCLEAR_R
Ethernet interface.
Definition: nic.h:79