sc589_eth1_driver.c
Go to the documentation of this file.
1 /**
2  * @file sc589_eth1_driver.c
3  * @brief ADSP-SC589 Ethernet MAC driver (EMAC0 instance)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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.6.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include <sys/platform.h>
36 #include <services/int/adi_int.h>
37 #include "core/net.h"
39 #include "debug.h"
40 
41 //Underlying network interface
42 static NetInterface *nicDriverInterface;
43 
44 //IAR EWARM compiler?
45 #if defined(__ICCARM__)
46 
47 //Transmit buffer
48 #pragma data_alignment = 4
49 #pragma location = SC589_ETH1_RAM_SECTION
51 //Receive buffer
52 #pragma data_alignment = 4
53 #pragma location = SC589_ETH1_RAM_SECTION
55 //Transmit DMA descriptors
56 #pragma data_alignment = 8
57 #pragma location = SC589_ETH1_RAM_SECTION
59 //Receive DMA descriptors
60 #pragma data_alignment = 8
61 #pragma location = SC589_ETH1_RAM_SECTION
63 
64 //GCC compiler?
65 #else
66 
67 //Transmit buffer
69  __attribute__((aligned(4), __section__(SC589_ETH1_RAM_SECTION)));
70 //Receive buffer
72  __attribute__((aligned(4), __section__(SC589_ETH1_RAM_SECTION)));
73 //Transmit DMA descriptors
75  __attribute__((aligned(8), __section__(SC589_ETH1_RAM_SECTION)));
76 //Receive DMA descriptors
78  __attribute__((aligned(8), __section__(SC589_ETH1_RAM_SECTION)));
79 
80 #endif
81 
82 //Pointer to the current TX DMA descriptor
83 static Sc589Eth1TxDmaDesc *txCurDmaDesc;
84 //Pointer to the current RX DMA descriptor
85 static Sc589Eth1RxDmaDesc *rxCurDmaDesc;
86 
87 
88 /**
89  * @brief ADSP-SC589 Ethernet MAC driver (EMAC0 instance)
90  **/
91 
93 {
95  ETH_MTU,
106  TRUE,
107  TRUE,
108  TRUE,
109  FALSE
110 };
111 
112 
113 /**
114  * @brief ADSP-SC589 Ethernet MAC initialization
115  * @param[in] interface Underlying network interface
116  * @return Error code
117  **/
118 
120 {
121  error_t error;
122 
123  //Debug message
124  TRACE_INFO("Initializing ADSP-SC589 Ethernet MAC (EMAC0)...\r\n");
125 
126  //Save underlying network interface
127  nicDriverInterface = interface;
128 
129  //GPIO configuration
130  sc589Eth1InitGpio(interface);
131 
132  //Perform a software reset
133  *pREG_EMAC0_DMA0_BUSMODE |= BITM_EMAC_DMA0_BUSMODE_SWR;
134  //Wait for the reset to complete
135  while((*pREG_EMAC0_DMA0_BUSMODE & BITM_EMAC_DMA0_BUSMODE_SWR) != 0)
136  {
137  }
138 
139  //Adjust MDC clock range depending on CLKO7 frequency
140  *pREG_EMAC0_SMI_ADDR = ENUM_EMAC_SMI_ADDR_CR_DIV62;
141 
142  //Valid Ethernet PHY or switch driver?
143  if(interface->phyDriver != NULL)
144  {
145  //Ethernet PHY initialization
146  error = interface->phyDriver->init(interface);
147  }
148  else if(interface->switchDriver != NULL)
149  {
150  //Ethernet switch initialization
151  error = interface->switchDriver->init(interface);
152  }
153  else
154  {
155  //The interface is not properly configured
156  error = ERROR_FAILURE;
157  }
158 
159  //Any error to report?
160  if(error)
161  {
162  return error;
163  }
164 
165  //Use default MAC configuration
166  *pREG_EMAC0_MACCFG = BITM_EMAC_MACCFG_PS | BITM_EMAC_MACCFG_DO;
167 
168  //Configure MAC address filtering
169  sc589Eth1UpdateMacAddrFilter(interface);
170 
171  //Disable flow control
172  *pREG_EMAC0_FLOWCTL = 0;
173 
174  //Enable store and forward mode
175  *pREG_EMAC0_DMA0_OPMODE = BITM_EMAC_DMA0_OPMODE_RSF |
176  BITM_EMAC_DMA0_OPMODE_TSF;
177 
178  //Configure DMA bus mode
179  *pREG_EMAC0_DMA0_BUSMODE = BITM_EMAC_DMA0_BUSMODE_AAL |
180  BITM_EMAC_DMA0_BUSMODE_USP | ENUM_EMAC_DMA_BUSMODE_RPBL_32 |
181  ENUM_EMAC_DMA_BUSMODE_PBL_32 | BITM_EMAC_DMA0_BUSMODE_ATDS;
182 
183  //Initialize DMA descriptor lists
184  sc589Eth1InitDmaDesc(interface);
185 
186  //Prevent interrupts from being generated when statistic counters reach
187  //half their maximum value
188  *pREG_EMAC0_MMC_TXIMSK = 0x01FFFFFF;
189  *pREG_EMAC0_MMC_RXIMSK = 0x01FFFFFF;
190  *pREG_EMAC0_IPC_RXIMSK = 0x3FFFFFFF;
191 
192  //Disable MAC interrupts
193  *pREG_EMAC0_IMSK = BITM_EMAC_IMSK_LPIIM | BITM_EMAC_IMSK_TS;
194 
195  //Enable the desired DMA interrupts
196  *pREG_EMAC0_DMA0_IEN = BITM_EMAC_DMA0_IEN_NIE | BITM_EMAC_DMA0_IEN_RIE |
197  BITM_EMAC_DMA0_IEN_TIE;
198 
199  //Register interrupt handler
200  adi_int_InstallHandler(INTR_EMAC0_STAT, sc589Eth1IrqHandler, interface,
201  false);
202 
203  //Enable MAC transmission and reception
204  *pREG_EMAC0_MACCFG |= BITM_EMAC_MACCFG_TE | BITM_EMAC_MACCFG_RE;
205  //Enable DMA transmission and reception
206  *pREG_EMAC0_DMA0_OPMODE |= BITM_EMAC_DMA0_OPMODE_ST | BITM_EMAC_DMA0_OPMODE_SR;
207 
208  //Accept any packets from the upper layer
209  osSetEvent(&interface->nicTxEvent);
210 
211  //Successful initialization
212  return NO_ERROR;
213 }
214 
215 
216 /**
217  * @brief GPIO configuration
218  * @param[in] interface Underlying network interface
219  **/
220 
221 __weak_func void sc589Eth1InitGpio(NetInterface *interface)
222 {
223 //ADZS-SC589-EZLITE evaluation board?
224 #if defined(USE_ADZS_SC589_EZLITE)
225  uint32_t temp;
226 
227  //Configure PA_00 (ETH0_TXD0), PA_01 (ETH0_TXD1), PA_02 (ETH0_MDC),
228  //PA_03 (ETH0_MDIO), PA_04 (ETH0_RXD0), PA_05 (ETH0_RXD1),
229  //PA_06 (ETH0_RXCLK_REFCLK), PA_07 (ETH0_CRS), PA_08 (ETH0_RXD2),
230  //PA_09 (ETH0_RXD3), PA_10 (ETH0_TXEN), PA_11 (ETH0_TXCLK),
231  //PA_12 (ETH0_TXD2) and PA_13 (ETH0_TXD3)
232  temp = *pREG_PORTA_MUX;
233  temp = (temp & ~BITM_PORT_MUX_MUX0) | (0 << BITP_PORT_MUX_MUX0);
234  temp = (temp & ~BITM_PORT_MUX_MUX1) | (0 << BITP_PORT_MUX_MUX1);
235  temp = (temp & ~BITM_PORT_MUX_MUX2) | (0 << BITP_PORT_MUX_MUX2);
236  temp = (temp & ~BITM_PORT_MUX_MUX3) | (0 << BITP_PORT_MUX_MUX3);
237  temp = (temp & ~BITM_PORT_MUX_MUX4) | (0 << BITP_PORT_MUX_MUX4);
238  temp = (temp & ~BITM_PORT_MUX_MUX5) | (0 << BITP_PORT_MUX_MUX5);
239  temp = (temp & ~BITM_PORT_MUX_MUX6) | (0 << BITP_PORT_MUX_MUX6);
240  temp = (temp & ~BITM_PORT_MUX_MUX7) | (0 << BITP_PORT_MUX_MUX7);
241  temp = (temp & ~BITM_PORT_MUX_MUX8) | (0 << BITP_PORT_MUX_MUX8);
242  temp = (temp & ~BITM_PORT_MUX_MUX9) | (0 << BITP_PORT_MUX_MUX9);
243  temp = (temp & ~BITM_PORT_MUX_MUX10) | (0 << BITP_PORT_MUX_MUX10);
244  temp = (temp & ~BITM_PORT_MUX_MUX11) | (0 << BITP_PORT_MUX_MUX11);
245  temp = (temp & ~BITM_PORT_MUX_MUX12) | (0 << BITP_PORT_MUX_MUX12);
246  temp = (temp & ~BITM_PORT_MUX_MUX13) | (0 << BITP_PORT_MUX_MUX13);
247  *pREG_PORTA_MUX = temp;
248 
249  //Select peripheral mode
250  *pREG_PORTA_FER_SET = BITM_PORT_FER_PX0 | BITM_PORT_FER_PX1 |
251  BITM_PORT_FER_PX2 | BITM_PORT_FER_PX3 | BITM_PORT_FER_PX4 |
252  BITM_PORT_FER_PX5 | BITM_PORT_FER_PX6 | BITM_PORT_FER_PX7 |
253  BITM_PORT_FER_PX8 | BITM_PORT_FER_PX9 | BITM_PORT_FER_PX10 |
254  BITM_PORT_FER_PX11 | BITM_PORT_FER_PX12 | BITM_PORT_FER_PX13;
255 
256  //Configure ETH0_MD_INT (PC_15) as an input
257  *pREG_PORTC_FER_CLR = BITM_PORT_FER_PX15;
258  *pREG_PORTC_DIR_CLR = BITM_PORT_DIR_PX15;
259  *pREG_PORTC_INEN_SET = BITM_PORT_INEN_PX15;
260 
261  //Configure ETH0_RESET (PB_14) as an output
262  *pREG_PORTB_FER_CLR = BITM_PORT_FER_PX14;
263  *pREG_PORTB_DIR_SET = BITM_PORT_DIR_PX14;
264 
265  //Reset PHY transceiver (hard reset)
266  *pREG_PORTB_DATA_CLR = BITM_PORT_DATA_PX14;
267  sleep(10);
268  *pREG_PORTB_DATA_SET = BITM_PORT_DATA_PX14;
269  sleep(10);
270 
271  //Select RGMII interface mode
272  *pREG_PADS0_PCFG0 |= BITM_PADS_PCFG0_EMACPHYISEL;
273  //Reset PHY interface
274  *pREG_PADS0_PCFG0 |= BITM_PADS_PCFG0_EMACRESET;
275 
276 //ADZS-SC589-MINI evaluation board?
277 #elif defined(USE_ADZS_SC589_MINI)
278  uint32_t temp;
279 
280  //Configure PA_00 (ETH0_TXD0), PA_01 (ETH0_TXD1), PA_02 (ETH0_MDC),
281  //PA_03 (ETH0_MDIO), PA_04 (ETH0_RXD0), PA_05 (ETH0_RXD1),
282  //PA_06 (ETH0_RXCLK_REFCLK), PA_07 (ETH0_CRS), PA_08 (ETH0_RXD2),
283  //PA_09 (ETH0_RXD3), PA_10 (ETH0_TXEN), PA_11 (ETH0_TXCLK),
284  //PA_12 (ETH0_TXD2) and PA_13 (ETH0_TXD3)
285  temp = *pREG_PORTA_MUX;
286  temp = (temp & ~BITM_PORT_MUX_MUX0) | (0 << BITP_PORT_MUX_MUX0);
287  temp = (temp & ~BITM_PORT_MUX_MUX1) | (0 << BITP_PORT_MUX_MUX1);
288  temp = (temp & ~BITM_PORT_MUX_MUX2) | (0 << BITP_PORT_MUX_MUX2);
289  temp = (temp & ~BITM_PORT_MUX_MUX3) | (0 << BITP_PORT_MUX_MUX3);
290  temp = (temp & ~BITM_PORT_MUX_MUX4) | (0 << BITP_PORT_MUX_MUX4);
291  temp = (temp & ~BITM_PORT_MUX_MUX5) | (0 << BITP_PORT_MUX_MUX5);
292  temp = (temp & ~BITM_PORT_MUX_MUX6) | (0 << BITP_PORT_MUX_MUX6);
293  temp = (temp & ~BITM_PORT_MUX_MUX7) | (0 << BITP_PORT_MUX_MUX7);
294  temp = (temp & ~BITM_PORT_MUX_MUX8) | (0 << BITP_PORT_MUX_MUX8);
295  temp = (temp & ~BITM_PORT_MUX_MUX9) | (0 << BITP_PORT_MUX_MUX9);
296  temp = (temp & ~BITM_PORT_MUX_MUX10) | (0 << BITP_PORT_MUX_MUX10);
297  temp = (temp & ~BITM_PORT_MUX_MUX11) | (0 << BITP_PORT_MUX_MUX11);
298  temp = (temp & ~BITM_PORT_MUX_MUX12) | (0 << BITP_PORT_MUX_MUX12);
299  temp = (temp & ~BITM_PORT_MUX_MUX13) | (0 << BITP_PORT_MUX_MUX13);
300  *pREG_PORTA_MUX = temp;
301 
302  //Select peripheral mode
303  *pREG_PORTA_FER_SET = BITM_PORT_FER_PX0 | BITM_PORT_FER_PX1 |
304  BITM_PORT_FER_PX2 | BITM_PORT_FER_PX3 | BITM_PORT_FER_PX4 |
305  BITM_PORT_FER_PX5 | BITM_PORT_FER_PX6 | BITM_PORT_FER_PX7 |
306  BITM_PORT_FER_PX8 | BITM_PORT_FER_PX9 | BITM_PORT_FER_PX10 |
307  BITM_PORT_FER_PX11 | BITM_PORT_FER_PX12 | BITM_PORT_FER_PX13;
308 
309  //Configure ETH0_MD_INT (PC_15) as an input
310  *pREG_PORTC_FER_CLR = BITM_PORT_FER_PX15;
311  *pREG_PORTC_DIR_CLR = BITM_PORT_DIR_PX15;
312  *pREG_PORTC_INEN_SET = BITM_PORT_INEN_PX15;
313 
314  //Configure ETH0_RESET (PB_07) as an output
315  *pREG_PORTB_FER_CLR = BITM_PORT_FER_PX7;
316  *pREG_PORTB_DIR_SET = BITM_PORT_DIR_PX7;
317 
318  //Reset PHY transceiver (hard reset)
319  *pREG_PORTB_DATA_CLR = BITM_PORT_DATA_PX7;
320  sleep(10);
321  *pREG_PORTB_DATA_SET = BITM_PORT_DATA_PX7;
322  sleep(10);
323 
324  //Select RGMII interface mode
325  *pREG_PADS0_PCFG0 |= BITM_PADS_PCFG0_EMACPHYISEL;
326  //Reset PHY interface
327  *pREG_PADS0_PCFG0 |= BITM_PADS_PCFG0_EMACRESET;
328 #endif
329 }
330 
331 
332 /**
333  * @brief Initialize DMA descriptor lists
334  * @param[in] interface Underlying network interface
335  **/
336 
338 {
339  uint_t i;
340 
341  //Initialize TX DMA descriptor list
342  for(i = 0; i < SC589_ETH1_TX_BUFFER_COUNT; i++)
343  {
344  //Use chain structure rather than ring structure
346  //Initialize transmit buffer size
347  txDmaDesc[i].tdes1 = 0;
348 
349  //Transmit buffer address
350  txDmaDesc[i].tdes2 = adi_rtl_internal_to_system_addr(
351  (uint32_t) txBuffer[i], 1);
352 
353  //Next descriptor address
354  txDmaDesc[i].tdes3 = adi_rtl_internal_to_system_addr(
355  (uint32_t) &txDmaDesc[i + 1], 1);
356 
357  //Reserved fields
358  txDmaDesc[i].tdes4 = 0;
359  txDmaDesc[i].tdes5 = 0;
360  //Transmit frame time stamp
361  txDmaDesc[i].tdes6 = 0;
362  txDmaDesc[i].tdes7 = 0;
363  }
364 
365  //The last descriptor is chained to the first entry
366  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
367  //Point to the very first descriptor
368  txCurDmaDesc = &txDmaDesc[0];
369 
370  //Initialize RX DMA descriptor list
371  for(i = 0; i < SC589_ETH1_RX_BUFFER_COUNT; i++)
372  {
373  //The descriptor is initially owned by the DMA
374  rxDmaDesc[i].rdes0 = EMAC_RDES0_OWN;
375  //Use chain structure rather than ring structure
377 
378  //Receive buffer address
379  rxDmaDesc[i].rdes2 = adi_rtl_internal_to_system_addr(
380  (uint32_t) rxBuffer[i], 1);
381 
382  //Next descriptor address
383  rxDmaDesc[i].rdes3 = adi_rtl_internal_to_system_addr(
384  (uint32_t) &rxDmaDesc[i + 1], 1);
385 
386  //Extended status
387  rxDmaDesc[i].rdes4 = 0;
388  //Reserved field
389  rxDmaDesc[i].rdes5 = 0;
390  //Receive frame time stamp
391  rxDmaDesc[i].rdes6 = 0;
392  rxDmaDesc[i].rdes7 = 0;
393  }
394 
395  //The last descriptor is chained to the first entry
396  rxDmaDesc[i - 1].rdes3 = adi_rtl_internal_to_system_addr(
397  (uint32_t) &rxDmaDesc[0], 1);
398 
399  //Point to the very first descriptor
400  rxCurDmaDesc = &rxDmaDesc[0];
401 
402  //Start location of the TX descriptor list
403  *pREG_EMAC0_DMA0_TXDSC_ADDR = adi_rtl_internal_to_system_addr(
404  (uint32_t) txDmaDesc, 1);
405 
406  //Start location of the RX descriptor list
407  *pREG_EMAC0_DMA0_RXDSC_ADDR = adi_rtl_internal_to_system_addr(
408  (uint32_t) rxDmaDesc, 1);
409 }
410 
411 
412 /**
413  * @brief ADSP-SC589 Ethernet MAC timer handler
414  *
415  * This routine is periodically called by the TCP/IP stack to handle periodic
416  * operations such as polling the link state
417  *
418  * @param[in] interface Underlying network interface
419  **/
420 
421 void sc589Eth1Tick(NetInterface *interface)
422 {
423  //Valid Ethernet PHY or switch driver?
424  if(interface->phyDriver != NULL)
425  {
426  //Handle periodic operations
427  interface->phyDriver->tick(interface);
428  }
429  else if(interface->switchDriver != NULL)
430  {
431  //Handle periodic operations
432  interface->switchDriver->tick(interface);
433  }
434  else
435  {
436  //Just for sanity
437  }
438 }
439 
440 
441 /**
442  * @brief Enable interrupts
443  * @param[in] interface Underlying network interface
444  **/
445 
447 {
448  //Enable Ethernet MAC interrupts
449  adi_int_EnableInt(INTR_EMAC0_STAT, true);
450 
451  //Valid Ethernet PHY or switch driver?
452  if(interface->phyDriver != NULL)
453  {
454  //Enable Ethernet PHY interrupts
455  interface->phyDriver->enableIrq(interface);
456  }
457  else if(interface->switchDriver != NULL)
458  {
459  //Enable Ethernet switch interrupts
460  interface->switchDriver->enableIrq(interface);
461  }
462  else
463  {
464  //Just for sanity
465  }
466 }
467 
468 
469 /**
470  * @brief Disable interrupts
471  * @param[in] interface Underlying network interface
472  **/
473 
475 {
476  //Disable Ethernet MAC interrupts
477  adi_int_EnableInt(INTR_EMAC0_STAT, false);
478 
479  //Valid Ethernet PHY or switch driver?
480  if(interface->phyDriver != NULL)
481  {
482  //Disable Ethernet PHY interrupts
483  interface->phyDriver->disableIrq(interface);
484  }
485  else if(interface->switchDriver != NULL)
486  {
487  //Disable Ethernet switch interrupts
488  interface->switchDriver->disableIrq(interface);
489  }
490  else
491  {
492  //Just for sanity
493  }
494 }
495 
496 
497 /**
498  * @brief ADSP-SC589 Ethernet MAC interrupt service routine
499  * @param id Interrupt identifier
500  * @param param Unused parameter
501  **/
502 
503 void sc589Eth1IrqHandler(uint32_t id, void *param)
504 {
505  bool_t flag;
506  uint32_t status;
507 
508  //Interrupt service routine prologue
509  osEnterIsr();
510 
511  //This flag will be set if a higher priority task must be woken
512  flag = FALSE;
513 
514  //Read DMA status register
515  status = *pREG_EMAC0_DMA0_STAT;
516 
517  //Packet transmitted?
518  if((status & BITM_EMAC_DMA0_STAT_TI) != 0)
519  {
520  //Clear TI interrupt flag
521  *pREG_EMAC0_DMA0_STAT = BITM_EMAC_DMA0_STAT_TI;
522 
523  //Check whether the TX buffer is available for writing
524  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
525  {
526  //Notify the TCP/IP stack that the transmitter is ready to send
527  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
528  }
529  }
530 
531  //Packet received?
532  if((status & BITM_EMAC_DMA0_STAT_RI) != 0)
533  {
534  //Clear RI interrupt flag
535  *pREG_EMAC0_DMA0_STAT = BITM_EMAC_DMA0_STAT_RI;
536 
537  //Set event flag
538  nicDriverInterface->nicEvent = TRUE;
539  //Notify the TCP/IP stack of the event
540  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
541  }
542 
543  //Clear NIS interrupt flag
544  *pREG_EMAC0_DMA0_STAT = BITM_EMAC_DMA0_STAT_NIS;
545 
546  //Interrupt service routine epilogue
547  osExitIsr(flag);
548 }
549 
550 
551 /**
552  * @brief ADSP-SC589 Ethernet MAC event handler
553  * @param[in] interface Underlying network interface
554  **/
555 
557 {
558  error_t error;
559 
560  //Process all pending packets
561  do
562  {
563  //Read incoming packet
564  error = sc589Eth1ReceivePacket(interface);
565 
566  //No more data in the receive buffer?
567  } while(error != ERROR_BUFFER_EMPTY);
568 }
569 
570 
571 /**
572  * @brief Send a packet
573  * @param[in] interface Underlying network interface
574  * @param[in] buffer Multi-part buffer containing the data to send
575  * @param[in] offset Offset to the first data byte
576  * @param[in] ancillary Additional options passed to the stack along with
577  * the packet
578  * @return Error code
579  **/
580 
582  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
583 {
584  size_t length;
585 
586  //Retrieve the length of the packet
587  length = netBufferGetLength(buffer) - offset;
588 
589  //Check the frame length
591  {
592  //The transmitter can accept another packet
593  osSetEvent(&interface->nicTxEvent);
594  //Report an error
595  return ERROR_INVALID_LENGTH;
596  }
597 
598  //Make sure the current buffer is available for writing
599  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) != 0)
600  {
601  return ERROR_FAILURE;
602  }
603 
604  //Copy user data to the transmit buffer
605  netBufferRead((uint8_t *) adi_rtl_system_to_internal_addr(
606  txCurDmaDesc->tdes2), buffer, offset, length);
607 
608  //Write the number of bytes to send
609  txCurDmaDesc->tdes1 = length & EMAC_TDES1_TBS1;
610  //Set LS and FS flags as the data fits in a single buffer
611  txCurDmaDesc->tdes0 |= EMAC_TDES0_LS | EMAC_TDES0_FS;
612  //Give the ownership of the descriptor to the DMA
613  txCurDmaDesc->tdes0 |= EMAC_TDES0_OWN;
614 
615  //Data synchronization barrier
616  __asm("dsb");
617 
618  //Clear TU flag to resume processing
619  *pREG_EMAC0_DMA0_STAT = BITM_EMAC_DMA0_STAT_TU;
620  //Instruct the DMA to poll the transmit descriptor list
621  *pREG_EMAC0_DMA0_TXPOLL = 0;
622 
623  //Point to the next descriptor in the list
624  txCurDmaDesc = (Sc589Eth1TxDmaDesc *) adi_rtl_system_to_internal_addr(
625  txCurDmaDesc->tdes3);
626 
627  //Check whether the next buffer is available for writing
628  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
629  {
630  //The transmitter can accept another packet
631  osSetEvent(&interface->nicTxEvent);
632  }
633 
634  //Data successfully written
635  return NO_ERROR;
636 }
637 
638 
639 /**
640  * @brief Receive a packet
641  * @param[in] interface Underlying network interface
642  * @return Error code
643  **/
644 
646 {
647  error_t error;
648  size_t n;
649  NetRxAncillary ancillary;
650 
651  //Current buffer available for reading?
652  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_OWN) == 0)
653  {
654  //FS and LS flags should be set
655  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_FS) != 0 &&
656  (rxCurDmaDesc->rdes0 & EMAC_RDES0_LS) != 0)
657  {
658  //Make sure no error occurred
659  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_ES) == 0)
660  {
661  //Retrieve the length of the frame
662  n = (rxCurDmaDesc->rdes0 & EMAC_RDES0_FL) >> 16;
663  //Limit the number of data to read
665 
666  //Additional options can be passed to the stack along with the packet
667  ancillary = NET_DEFAULT_RX_ANCILLARY;
668 
669  //Pass the packet to the upper layer
670  nicProcessPacket(interface, (uint8_t *) adi_rtl_system_to_internal_addr(
671  rxCurDmaDesc->rdes2), n, &ancillary);
672 
673  //Valid packet received
674  error = NO_ERROR;
675  }
676  else
677  {
678  //The received packet contains an error
679  error = ERROR_INVALID_PACKET;
680  }
681  }
682  else
683  {
684  //The packet is not valid
685  error = ERROR_INVALID_PACKET;
686  }
687 
688  //Give the ownership of the descriptor back to the DMA
689  rxCurDmaDesc->rdes0 = EMAC_RDES0_OWN;
690 
691  //Point to the next descriptor in the list
692  rxCurDmaDesc = (Sc589Eth1RxDmaDesc *) adi_rtl_system_to_internal_addr(
693  rxCurDmaDesc->rdes3);
694  }
695  else
696  {
697  //No more data in the receive buffer
698  error = ERROR_BUFFER_EMPTY;
699  }
700 
701  //Clear RU flag to resume processing
702  *pREG_EMAC0_DMA0_STAT = BITM_EMAC_DMA0_STAT_RU;
703  //Instruct the DMA to poll the receive descriptor list
704  *pREG_EMAC0_DMA0_RXPOLL = 0;
705 
706  //Return status code
707  return error;
708 }
709 
710 
711 /**
712  * @brief Configure MAC address filtering
713  * @param[in] interface Underlying network interface
714  * @return Error code
715  **/
716 
718 {
719  uint_t i;
720  uint_t j;
721  uint_t k;
722  uint32_t crc;
723  uint32_t hashTable[2];
724  MacAddr unicastMacAddr[1];
725  MacFilterEntry *entry;
726 
727  //Debug message
728  TRACE_DEBUG("Updating MAC filter...\r\n");
729 
730  //Promiscuous mode?
731  if(interface->promiscuous)
732  {
733  //Pass all incoming frames regardless of their destination address
734  *pREG_EMAC0_MACFRMFILT = BITM_EMAC_MACFRMFILT_PR;
735  }
736  else
737  {
738  //Set the MAC address of the station
739  *pREG_EMAC0_ADDR0_LO = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
740  *pREG_EMAC0_ADDR0_HI = interface->macAddr.w[2];
741 
742  //The MAC supports one additional address for unicast perfect filtering
743  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
744 
745  //The hash table is used for multicast address filtering
746  hashTable[0] = 0;
747  hashTable[1] = 0;
748 
749  //The MAC address filter contains the list of MAC addresses to accept
750  //when receiving an Ethernet frame
751  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
752  {
753  //Point to the current entry
754  entry = &interface->macAddrFilter[i];
755 
756  //Valid entry?
757  if(entry->refCount > 0)
758  {
759  //Multicast address?
760  if(macIsMulticastAddr(&entry->addr))
761  {
762  //Compute CRC over the current MAC address
763  crc = sc589Eth1CalcCrc(&entry->addr, sizeof(MacAddr));
764 
765  //The upper 6 bits in the CRC register are used to index the
766  //contents of the hash table
767  k = (crc >> 26) & 0x3F;
768 
769  //Update hash table contents
770  hashTable[k / 32] |= (1 << (k % 32));
771  }
772  else
773  {
774  //One additional MAC address can be specified
775  if(j < 1)
776  {
777  //Save the unicast address
778  unicastMacAddr[j++] = entry->addr;
779  }
780  }
781  }
782  }
783 
784  //Configure the first unicast address filter
785  if(j >= 1)
786  {
787  //When the AE bit is set, the entry is used for perfect filtering
788  *pREG_EMAC0_ADDR1_LO = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
789  *pREG_EMAC0_ADDR1_HI = unicastMacAddr[0].w[2] | BITM_EMAC_ADDR1_HI_AE;
790  }
791  else
792  {
793  //When the AE bit is cleared, the entry is ignored
794  *pREG_EMAC0_ADDR1_LO = 0;
795  *pREG_EMAC0_ADDR1_HI = 0;
796  }
797 
798  //Check whether frames with a multicast destination address should be
799  //accepted
800  if(interface->acceptAllMulticast)
801  {
802  //Configure the receive filter
803  *pREG_EMAC0_MACFRMFILT = BITM_EMAC_MACFRMFILT_HPF | BITM_EMAC_MACFRMFILT_PM;
804  }
805  else
806  {
807  //Configure the receive filter
808  *pREG_EMAC0_MACFRMFILT = BITM_EMAC_MACFRMFILT_HPF | BITM_EMAC_MACFRMFILT_HMC;
809 
810  //Configure the multicast hash table
811  *pREG_EMAC0_HASHTBL_LO = hashTable[0];
812  *pREG_EMAC0_HASHTBL_HI = hashTable[1];
813 
814  //Debug message
815  TRACE_DEBUG(" EMAC_HASHTBL_LO = 0x%08" PRIX32 "\r\n", *pREG_EMAC0_HASHTBL_LO);
816  TRACE_DEBUG(" EMAC_HASHTBL_HI = 0x%08" PRIX32 "\r\n", *pREG_EMAC0_HASHTBL_HI);
817  }
818  }
819 
820  //Successful processing
821  return NO_ERROR;
822 }
823 
824 
825 /**
826  * @brief Adjust MAC configuration parameters for proper operation
827  * @param[in] interface Underlying network interface
828  * @return Error code
829  **/
830 
832 {
833  uint32_t config;
834 
835  //Read current MAC configuration
836  config = *pREG_EMAC0_MACCFG;
837 
838  //1000BASE-T operation mode?
839  if(interface->linkSpeed == NIC_LINK_SPEED_1GBPS)
840  {
841  config &= ~BITM_EMAC_MACCFG_PS;
842  config &= ~BITM_EMAC_MACCFG_FES;
843  }
844  //100BASE-TX operation mode?
845  else if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
846  {
847  config |= BITM_EMAC_MACCFG_PS;
848  config |= BITM_EMAC_MACCFG_FES;
849  }
850  //10BASE-T operation mode?
851  else
852  {
853  config |= BITM_EMAC_MACCFG_PS;
854  config &= ~BITM_EMAC_MACCFG_FES;
855  }
856 
857  //Half-duplex or full-duplex mode?
858  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
859  {
860  config |= BITM_EMAC_MACCFG_DM;
861  }
862  else
863  {
864  config &= ~BITM_EMAC_MACCFG_DM;
865  }
866 
867  //Update MAC configuration register
868  *pREG_EMAC0_MACCFG = config;
869 
870  //Successful processing
871  return NO_ERROR;
872 }
873 
874 
875 /**
876  * @brief Write PHY register
877  * @param[in] opcode Access type (2 bits)
878  * @param[in] phyAddr PHY address (5 bits)
879  * @param[in] regAddr Register address (5 bits)
880  * @param[in] data Register value
881  **/
882 
883 void sc589Eth1WritePhyReg(uint8_t opcode, uint8_t phyAddr,
884  uint8_t regAddr, uint16_t data)
885 {
886  uint32_t temp;
887 
888  //Valid opcode?
889  if(opcode == SMI_OPCODE_WRITE)
890  {
891  //Take care not to alter MDC clock configuration
892  temp = *pREG_EMAC0_SMI_ADDR & BITM_EMAC_SMI_ADDR_CR;
893  //Set up a write operation
894  temp |= BITM_EMAC_SMI_ADDR_SMIW | BITM_EMAC_SMI_ADDR_SMIB;
895  //PHY address
896  temp |= (phyAddr << BITP_EMAC_SMI_ADDR_PA) & BITM_EMAC_SMI_ADDR_PA;
897  //Register address
898  temp |= (regAddr << BITP_EMAC_SMI_ADDR_SMIR) & BITM_EMAC_SMI_ADDR_SMIR;
899 
900  //Data to be written in the PHY register
901  *pREG_EMAC0_SMI_DATA = data & BITM_EMAC_SMI_DATA_SMID;
902 
903  //Start a write operation
904  *pREG_EMAC0_SMI_ADDR = temp;
905  //Wait for the write to complete
906  while((*pREG_EMAC0_SMI_ADDR & BITM_EMAC_SMI_ADDR_SMIB) != 0)
907  {
908  }
909  }
910  else
911  {
912  //The MAC peripheral only supports standard Clause 22 opcodes
913  }
914 }
915 
916 
917 /**
918  * @brief Read PHY register
919  * @param[in] opcode Access type (2 bits)
920  * @param[in] phyAddr PHY address (5 bits)
921  * @param[in] regAddr Register address (5 bits)
922  * @return Register value
923  **/
924 
925 uint16_t sc589Eth1ReadPhyReg(uint8_t opcode, uint8_t phyAddr,
926  uint8_t regAddr)
927 {
928  uint16_t data;
929  uint32_t temp;
930 
931  //Valid opcode?
932  if(opcode == SMI_OPCODE_READ)
933  {
934  //Take care not to alter MDC clock configuration
935  temp = *pREG_EMAC0_SMI_ADDR & BITM_EMAC_SMI_ADDR_CR;
936  //Set up a read operation
937  temp |= BITM_EMAC_SMI_ADDR_SMIB;
938  //PHY address
939  temp |= (phyAddr << BITP_EMAC_SMI_ADDR_PA) & BITM_EMAC_SMI_ADDR_PA;
940  //Register address
941  temp |= (regAddr << BITP_EMAC_SMI_ADDR_SMIR) & BITM_EMAC_SMI_ADDR_SMIR;
942 
943  //Start a read operation
944  *pREG_EMAC0_SMI_ADDR = temp;
945  //Wait for the read to complete
946  while((*pREG_EMAC0_SMI_ADDR & BITM_EMAC_SMI_ADDR_SMIB) != 0)
947  {
948  }
949 
950  //Get register value
951  data = *pREG_EMAC0_SMI_DATA & BITM_EMAC_SMI_DATA_SMID;
952  }
953  else
954  {
955  //The MAC peripheral only supports standard Clause 22 opcodes
956  data = 0;
957  }
958 
959  //Return the value of the PHY register
960  return data;
961 }
962 
963 
964 /**
965  * @brief CRC calculation
966  * @param[in] data Pointer to the data over which to calculate the CRC
967  * @param[in] length Number of bytes to process
968  * @return Resulting CRC value
969  **/
970 
971 uint32_t sc589Eth1CalcCrc(const void *data, size_t length)
972 {
973  uint_t i;
974  uint_t j;
975  uint32_t crc;
976  const uint8_t *p;
977 
978  //Point to the data over which to calculate the CRC
979  p = (uint8_t *) data;
980  //CRC preset value
981  crc = 0xFFFFFFFF;
982 
983  //Loop through data
984  for(i = 0; i < length; i++)
985  {
986  //The message is processed bit by bit
987  for(j = 0; j < 8; j++)
988  {
989  //Update CRC value
990  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
991  {
992  crc = (crc << 1) ^ 0x04C11DB7;
993  }
994  else
995  {
996  crc = crc << 1;
997  }
998  }
999  }
1000 
1001  //Return CRC value
1002  return ~crc;
1003 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define ENUM_EMAC_SMI_ADDR_CR_DIV62
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define EMAC_RDES1_RBS1
uint8_t opcode
Definition: dns_common.h:191
int bool_t
Definition: compiler_port.h:63
void sc589Eth1InitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
void sc589Eth1EventHandler(NetInterface *interface)
ADSP-SC589 Ethernet MAC event handler.
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:690
error_t sc589Eth1SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define EMAC_TDES0_OWN
uint8_t p
Definition: ndp.h:300
#define EMAC_RDES0_ES
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
#define sleep(delay)
Definition: os_port.h:310
error_t sc589Eth1UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
#define EMAC_TDES0_IC
void sc589Eth1EnableIrq(NetInterface *interface)
Enable interrupts.
error_t sc589Eth1Init(NetInterface *interface)
ADSP-SC589 Ethernet MAC initialization.
#define ENUM_EMAC_DMA_BUSMODE_RPBL_32
#define SC589_ETH1_TX_BUFFER_COUNT
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define SC589_ETH1_TX_BUFFER_SIZE
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define FALSE
Definition: os_port.h:46
#define EMAC_RDES1_RCH
#define EMAC_TDES1_TBS1
#define EMAC_RDES0_LS
void sc589Eth1IrqHandler(uint32_t id, void *param)
ADSP-SC589 Ethernet MAC interrupt service routine.
error_t
Error codes.
Definition: error.h:43
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define txBuffer
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
MacAddr addr
MAC address.
Definition: ethernet.h:265
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void sc589Eth1WritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
#define NetTxAncillary
Definition: net_misc.h:36
#define SMI_OPCODE_READ
Definition: nic.h:67
uint32_t sc589Eth1CalcCrc(const void *data, size_t length)
CRC calculation.
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MIN(a, b)
Definition: os_port.h:63
#define EMAC_TDES0_LS
#define rxBuffer
MacAddr
Definition: ethernet.h:197
#define EMAC_TDES0_TCH
Enhanced RX DMA descriptor.
#define EMAC_RDES0_FL
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define ENUM_EMAC_DMA_BUSMODE_PBL_32
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
ADSP-SC589 Ethernet MAC driver (EMAC0 instance)
uint16_t sc589Eth1ReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define SC589_ETH1_RX_BUFFER_SIZE
#define osEnterIsr()
#define SC589_ETH1_RX_BUFFER_COUNT
Enhanced TX DMA descriptor.
error_t sc589Eth1ReceivePacket(NetInterface *interface)
Receive a packet.
#define EMAC_TDES0_FS
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
const NicDriver sc589Eth1Driver
ADSP-SC589 Ethernet MAC driver (EMAC0 instance)
#define txDmaDesc
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
__weak_func void sc589Eth1InitGpio(NetInterface *interface)
GPIO configuration.
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
void sc589Eth1Tick(NetInterface *interface)
ADSP-SC589 Ethernet MAC timer handler.
NIC driver.
Definition: nic.h:286
#define EMAC_RDES0_OWN
error_t sc589Eth1UpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
@ NO_ERROR
Success.
Definition: error.h:44
#define SC589_ETH1_RAM_SECTION
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define EMAC_RDES0_FS
void sc589Eth1DisableIrq(NetInterface *interface)
Disable interrupts.