mcimx6ul_eth1_driver.c
Go to the documentation of this file.
1 /**
2  * @file mcimx6ul_eth1_driver.c
3  * @brief i.MX6UL Ethernet MAC controller (ENET1 instance)
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.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "fsl_device_registers.h"
36 #include "fsl_gpio.h"
37 #include "fsl_iomuxc.h"
38 #include "core/net.h"
40 #include "debug.h"
41 
42 //Underlying network interface
43 static NetInterface *nicDriverInterface;
44 
45 //IAR EWARM compiler?
46 #if defined(__ICCARM__)
47 
48 //TX buffer
49 #pragma data_alignment = 16
50 #pragma location = "NonCacheable"
52 //RX buffer
53 #pragma data_alignment = 16
54 #pragma location = "NonCacheable"
56 //TX buffer descriptors
57 #pragma data_alignment = 16
58 #pragma location = "NonCacheable"
59 static uint32_t txBufferDesc[MCIMX6UL_ETH1_TX_BUFFER_COUNT][8];
60 //RX buffer descriptors
61 #pragma data_alignment = 16
62 #pragma location = "NonCacheable"
63 static uint32_t rxBufferDesc[MCIMX6UL_ETH1_RX_BUFFER_COUNT][8];
64 
65 //ARM or GCC compiler?
66 #else
67 
68 //TX buffer
70  __attribute__((aligned(16), __section__("NonCacheable")));
71 //RX buffer
73  __attribute__((aligned(16), __section__("NonCacheable")));
74 //TX buffer descriptors
75 static uint32_t txBufferDesc[MCIMX6UL_ETH1_TX_BUFFER_COUNT][8]
76  __attribute__((aligned(16), __section__("NonCacheable")));
77 //RX buffer descriptors
78 static uint32_t rxBufferDesc[MCIMX6UL_ETH1_RX_BUFFER_COUNT][8]
79  __attribute__((aligned(16), __section__("NonCacheable")));
80 
81 #endif
82 
83 //TX buffer index
84 static uint_t txBufferIndex;
85 //RX buffer index
86 static uint_t rxBufferIndex;
87 
88 
89 /**
90  * @brief i.MX6UL Ethernet MAC driver
91  **/
92 
94 {
96  ETH_MTU,
107  TRUE,
108  TRUE,
109  TRUE,
110  FALSE
111 };
112 
113 
114 /**
115  * @brief i.MX6UL Ethernet MAC initialization
116  * @param[in] interface Underlying network interface
117  * @return Error code
118  **/
119 
121 {
122  error_t error;
123  uint32_t value;
124 
125  //Debug message
126  TRACE_INFO("Initializing i.MX6UL Ethernet MAC #1...\r\n");
127 
128  //Save underlying network interface
129  nicDriverInterface = interface;
130 
131  //Enable ENET peripheral clock
132  CLOCK_EnableClock(kCLOCK_Enet);
133 
134  //GPIO configuration
135  mcimx6ulEth1InitGpio(interface);
136 
137  //Reset ENET module
138  ENET1->ECR = ENET_ECR_RESET_MASK;
139  //Wait for the reset to complete
140  while(ENET1->ECR & ENET_ECR_RESET_MASK);
141 
142  //Receive control register
143  ENET1->RCR = ENET_RCR_MAX_FL(MCIMX6UL_ETH1_RX_BUFFER_SIZE) |
144  ENET_RCR_RMII_MODE_MASK | ENET_RCR_MII_MODE_MASK;
145 
146  //Transmit control register
147  ENET1->TCR = 0;
148  //Configure MDC clock frequency
149  ENET1->MSCR = ENET_MSCR_HOLDTIME(10) | ENET_MSCR_MII_SPEED(120);
150 
151  //PHY transceiver initialization
152  error = interface->phyDriver->init(interface);
153  //Failed to initialize PHY transceiver?
154  if(error)
155  return error;
156 
157  //Set the MAC address of the station (upper 16 bits)
158  value = interface->macAddr.b[5];
159  value |= (interface->macAddr.b[4] << 8);
160  ENET1->PAUR = ENET_PAUR_PADDR2(value) | ENET_PAUR_TYPE(0x8808);
161 
162  //Set the MAC address of the station (lower 32 bits)
163  value = interface->macAddr.b[3];
164  value |= (interface->macAddr.b[2] << 8);
165  value |= (interface->macAddr.b[1] << 16);
166  value |= (interface->macAddr.b[0] << 24);
167  ENET1->PALR = ENET_PALR_PADDR1(value);
168 
169  //Hash table for unicast address filtering
170  ENET1->IALR = 0;
171  ENET1->IAUR = 0;
172  //Hash table for multicast address filtering
173  ENET1->GALR = 0;
174  ENET1->GAUR = 0;
175 
176  //Disable transmit accelerator functions
177  ENET1->TACC = 0;
178  //Disable receive accelerator functions
179  ENET1->RACC = 0;
180 
181  //Use enhanced buffer descriptors
182  ENET1->ECR = ENET_ECR_DBSWP_MASK | ENET_ECR_EN1588_MASK;
183  //Clear MIC counters
184  ENET1->MIBC = ENET_MIBC_MIB_CLEAR_MASK;
185 
186  //Initialize buffer descriptors
187  mcimx6ulEth1InitBufferDesc(interface);
188 
189  //Clear any pending interrupts
190  ENET1->EIR = 0xFFFFFFFF;
191  //Enable desired interrupts
192  ENET1->EIMR = ENET_EIMR_TXF_MASK | ENET_EIMR_RXF_MASK | ENET_EIMR_EBERR_MASK;
193 
194  //Configure ENET interrupt priority
195  GIC_SetPriority(ENET1_IRQn, MCIMX6UL_ETH1_IRQ_PRIORITY);
196 
197  //Enable Ethernet MAC
198  ENET1->ECR |= ENET_ECR_ETHEREN_MASK;
199  //Instruct the DMA to poll the receive descriptor list
200  ENET1->RDAR = ENET_RDAR_RDAR_MASK;
201 
202  //Accept any packets from the upper layer
203  osSetEvent(&interface->nicTxEvent);
204 
205  //Successful initialization
206  return NO_ERROR;
207 }
208 
209 
210 //MCIMX6UL-EVKB or MCIMX6ULL-EVK evaluation board?
211 #if defined(USE_MCIMX6UL_EVKB) || defined(USE_MCIMX6ULL_EVK)
212 
213 /**
214  * @brief GPIO configuration
215  * @param[in] interface Underlying network interface
216  **/
217 
218 void mcimx6ulEth1InitGpio(NetInterface *interface)
219 {
220  gpio_pin_config_t pinConfig;
221  clock_enet_pll_config_t pllConfig;
222 
223  //Configure ENET PLL (50MHz)
224  pllConfig.enableClkOutput0 = true;
225  pllConfig.enableClkOutput1 = true;
226  pllConfig.enableClkOutput2 = false;
227  pllConfig.loopDivider0 = 1;
228  pllConfig.loopDivider1 = 1;
229  CLOCK_InitEnetPll(&pllConfig);
230 
231  //Enable ENET1_TX_CLK output driver
232  IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_ENET1_TX_CLK_DIR(1);
233 
234  //Enable IOMUXC clock
235  CLOCK_EnableClock(kCLOCK_Iomuxc);
236 
237  //Configure ENET1_TX_CLK pin as ENET1_REF_CLK1
238  IOMUXC_SetPinMux(IOMUXC_ENET1_TX_CLK_ENET1_REF_CLK1, 1);
239 
240  //Set ENET1_TX_CLK pad properties
241  IOMUXC_SetPinConfig(IOMUXC_ENET1_TX_CLK_ENET1_REF_CLK1,
242  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
243  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
244  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
245  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
246  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
247  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
248  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
249  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
250 
251  //Configure ENET1_TX_EN pin as ENET1_TX_EN
252  IOMUXC_SetPinMux(IOMUXC_ENET1_TX_EN_ENET1_TX_EN, 0);
253 
254  //Set ENET1_TX_EN pad properties
255  IOMUXC_SetPinConfig(IOMUXC_ENET1_TX_EN_ENET1_TX_EN,
256  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
257  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
258  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
259  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
260  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
261  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
262  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
263  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
264 
265  //Configure ENET1_TX_DATA0 pin as ENET1_TDATA00
266  IOMUXC_SetPinMux(IOMUXC_ENET1_TX_DATA0_ENET1_TDATA00, 0);
267 
268  //Set ENET1_TX_DATA0 pad properties
269  IOMUXC_SetPinConfig(IOMUXC_ENET1_TX_DATA0_ENET1_TDATA00,
270  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
271  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
272  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
273  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
274  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
275  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
276  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
277  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
278 
279  //Configure ENET1_TX_DATA1 pin as ENET1_TDATA01
280  IOMUXC_SetPinMux(IOMUXC_ENET1_TX_DATA1_ENET1_TDATA01, 0);
281 
282  //Set ENET1_TX_DATA1 pad properties
283  IOMUXC_SetPinConfig(IOMUXC_ENET1_TX_DATA1_ENET1_TDATA01,
284  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
285  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
286  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
287  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
288  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
289  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
290  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
291  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
292 
293  //Configure ENET1_RX_EN pin as ENET1_RX_EN
294  IOMUXC_SetPinMux(IOMUXC_ENET1_RX_EN_ENET1_RX_EN, 0);
295 
296  //Set ENET1_RX_EN pad properties
297  IOMUXC_SetPinConfig(IOMUXC_ENET1_RX_EN_ENET1_RX_EN,
298  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
299  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
300  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
301  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
302  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
303  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
304  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
305  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
306 
307  //Configure ENET1_RX_ER pin as ENET1_RX_ER
308  IOMUXC_SetPinMux(IOMUXC_ENET1_RX_ER_ENET1_RX_ER, 0);
309 
310  //Set ENET1_RX_ER pad properties
311  IOMUXC_SetPinConfig(IOMUXC_ENET1_RX_ER_ENET1_RX_ER,
312  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
313  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
314  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
315  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
316  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
317  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
318  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
319  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
320 
321  //Configure ENET1_RX_DATA0 pin as ENET1_RDATA00
322  IOMUXC_SetPinMux(IOMUXC_ENET1_RX_DATA0_ENET1_RDATA00, 0);
323 
324  //Set ENET1_RX_DATA0 pad properties
325  IOMUXC_SetPinConfig(IOMUXC_ENET1_RX_DATA0_ENET1_RDATA00,
326  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
327  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
328  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
329  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
330  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
331  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
332  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
333  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
334 
335  //Configure ENET1_RX_DATA1 pin as ENET1_RDATA01
336  IOMUXC_SetPinMux(IOMUXC_ENET1_RX_DATA1_ENET1_RDATA01, 0);
337 
338  //Set ENET1_RX_DATA1 pad properties
339  IOMUXC_SetPinConfig(IOMUXC_ENET1_RX_DATA1_ENET1_RDATA01,
340  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
341  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
342  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
343  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
344  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
345  IOMUXC_SW_PAD_CTL_PAD_SPEED(3) |
346  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
347  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
348 
349  //Configure GPIO1_IO06 pin as ENET1_MDIO
350  IOMUXC_SetPinMux(IOMUXC_GPIO1_IO06_ENET1_MDIO, 0);
351 
352  //Set GPIO1_IO06 pad properties
353  IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO06_ENET1_MDIO,
354  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
355  IOMUXC_SW_PAD_CTL_PAD_PUS(2) |
356  IOMUXC_SW_PAD_CTL_PAD_PUE(1) |
357  IOMUXC_SW_PAD_CTL_PAD_PKE(1) |
358  IOMUXC_SW_PAD_CTL_PAD_ODE(1) |
359  IOMUXC_SW_PAD_CTL_PAD_SPEED(0) |
360  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
361  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
362 
363  //Configure GPIO1_IO07 pin as ENET1_MDC
364  IOMUXC_SetPinMux(IOMUXC_GPIO1_IO07_ENET1_MDC, 0);
365 
366  //Set GPIO1_IO07 pad properties
367  IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO07_ENET1_MDC,
368  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
369  IOMUXC_SW_PAD_CTL_PAD_PUS(0) |
370  IOMUXC_SW_PAD_CTL_PAD_PUE(0) |
371  IOMUXC_SW_PAD_CTL_PAD_PKE(0) |
372  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
373  IOMUXC_SW_PAD_CTL_PAD_SPEED(0) |
374  IOMUXC_SW_PAD_CTL_PAD_DSE(5) |
375  IOMUXC_SW_PAD_CTL_PAD_SRE(1));
376 
377 #if defined(USE_MCIMX6UL_EVKB)
378  //Configure SNVS_TAMPER5 pin as GPIO5_IO05
379  IOMUXC_SetPinMux(IOMUXC_SNVS_TAMPER5_GPIO5_IO05, 0);
380 
381  //Set SNVS_TAMPER5 pad properties
382  IOMUXC_SetPinConfig(IOMUXC_SNVS_TAMPER5_GPIO5_IO05,
383  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
384  IOMUXC_SW_PAD_CTL_PAD_PUS(2) |
385  IOMUXC_SW_PAD_CTL_PAD_PUE(1) |
386  IOMUXC_SW_PAD_CTL_PAD_PKE(1) |
387  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
388  IOMUXC_SW_PAD_CTL_PAD_SPEED(0) |
389  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
390  IOMUXC_SW_PAD_CTL_PAD_SRE(0));
391 
392 #elif defined(USE_MCIMX6ULL_EVK)
393  //Configure SNVS_TAMPER5 pin as GPIO5_IO05
394  IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER5_GPIO5_IO05, 0);
395 
396  //Set SNVS_TAMPER5 pad properties
397  IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER5_GPIO5_IO05,
398  IOMUXC_SW_PAD_CTL_PAD_HYS(0) |
399  IOMUXC_SW_PAD_CTL_PAD_PUS(2) |
400  IOMUXC_SW_PAD_CTL_PAD_PUE(1) |
401  IOMUXC_SW_PAD_CTL_PAD_PKE(1) |
402  IOMUXC_SW_PAD_CTL_PAD_ODE(0) |
403  IOMUXC_SW_PAD_CTL_PAD_SPEED(0) |
404  IOMUXC_SW_PAD_CTL_PAD_DSE(0) |
405  IOMUXC_SW_PAD_CTL_PAD_SRE(0));
406 #endif
407 
408  //Configure ENET1_INT as an input
409  pinConfig.direction = kGPIO_DigitalInput;
410  pinConfig.outputLogic = 0;
411  pinConfig.interruptMode = kGPIO_NoIntmode;
412  GPIO_PinInit(GPIO5, 5, &pinConfig);
413 }
414 
415 #endif
416 
417 
418 /**
419  * @brief Initialize buffer descriptors
420  * @param[in] interface Underlying network interface
421  **/
422 
424 {
425  uint_t i;
426  uint32_t address;
427 
428  //Clear TX and RX buffer descriptors
429  memset(txBufferDesc, 0, sizeof(txBufferDesc));
430  memset(rxBufferDesc, 0, sizeof(rxBufferDesc));
431 
432  //Initialize TX buffer descriptors
433  for(i = 0; i < MCIMX6UL_ETH1_TX_BUFFER_COUNT; i++)
434  {
435  //Calculate the address of the current TX buffer
436  address = (uint32_t) txBuffer[i];
437  //Transmit buffer address
438  txBufferDesc[i][1] = address;
439  //Generate interrupts
440  txBufferDesc[i][2] = ENET_TBD2_INT;
441  }
442 
443  //Mark the last descriptor entry with the wrap flag
444  txBufferDesc[i - 1][0] |= ENET_TBD0_W;
445  //Initialize TX buffer index
446  txBufferIndex = 0;
447 
448  //Initialize RX buffer descriptors
449  for(i = 0; i < MCIMX6UL_ETH1_RX_BUFFER_COUNT; i++)
450  {
451  //Calculate the address of the current RX buffer
452  address = (uint32_t) rxBuffer[i];
453  //The descriptor is initially owned by the DMA
454  rxBufferDesc[i][0] = ENET_RBD0_E;
455  //Receive buffer address
456  rxBufferDesc[i][1] = address;
457  //Generate interrupts
458  rxBufferDesc[i][2] = ENET_RBD2_INT;
459  }
460 
461  //Mark the last descriptor entry with the wrap flag
462  rxBufferDesc[i - 1][0] |= ENET_RBD0_W;
463  //Initialize RX buffer index
464  rxBufferIndex = 0;
465 
466  //Start location of the TX descriptor list
467  ENET1->TDSR = (uint32_t) txBufferDesc;
468  //Start location of the RX descriptor list
469  ENET1->RDSR = (uint32_t) rxBufferDesc;
470  //Maximum receive buffer size
471  ENET1->MRBR = MCIMX6UL_ETH1_RX_BUFFER_SIZE;
472 }
473 
474 
475 /**
476  * @brief i.MX6UL Ethernet MAC timer handler
477  *
478  * This routine is periodically called by the TCP/IP stack to
479  * handle periodic operations such as polling the link state
480  *
481  * @param[in] interface Underlying network interface
482  **/
483 
485 {
486  //Handle periodic operations
487  interface->phyDriver->tick(interface);
488 }
489 
490 
491 /**
492  * @brief Enable interrupts
493  * @param[in] interface Underlying network interface
494  **/
495 
497 {
498  //Enable Ethernet MAC interrupts
499  GIC_EnableIRQ(ENET1_IRQn);
500  //Enable Ethernet PHY interrupts
501  interface->phyDriver->enableIrq(interface);
502 }
503 
504 
505 /**
506  * @brief Disable interrupts
507  * @param[in] interface Underlying network interface
508  **/
509 
511 {
512  //Disable Ethernet MAC interrupts
513  GIC_DisableIRQ(ENET1_IRQn);
514  //Disable Ethernet PHY interrupts
515  interface->phyDriver->disableIrq(interface);
516 }
517 
518 
519 /**
520  * @brief Ethernet MAC interrupt (ENET1 instance)
521  * @param[in] giccIar Value of the GICC_IAR register
522  * @param[in] userParam User parameter
523  **/
524 
525 void ENET1_DriverIRQHandler (uint32_t giccIar, void *userParam)
526 {
527  bool_t flag;
528  uint32_t events;
529 
530  //Enter interrupt service routine
531  osEnterIsr();
532 
533  //This flag will be set if a higher priority task must be woken
534  flag = FALSE;
535  //Read interrupt event register
536  events = ENET1->EIR;
537 
538  //A packet has been transmitted?
539  if(events & ENET_EIR_TXF_MASK)
540  {
541  //Clear TXF interrupt flag
542  ENET1->EIR = ENET_EIR_TXF_MASK;
543 
544  //Check whether the TX buffer is available for writing
545  if(!(txBufferDesc[txBufferIndex][0] & ENET_TBD0_R))
546  {
547  //Notify the TCP/IP stack that the transmitter is ready to send
548  flag = osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
549  }
550 
551  //Instruct the DMA to poll the transmit descriptor list
552  ENET1->TDAR = ENET_TDAR_TDAR_MASK;
553  }
554 
555  //A packet has been received?
556  if(events & ENET_EIR_RXF_MASK)
557  {
558  //Disable RXF interrupt
559  ENET1->EIMR &= ~ENET_EIMR_RXF_MASK;
560 
561  //Set event flag
562  nicDriverInterface->nicEvent = TRUE;
563  //Notify the TCP/IP stack of the event
564  flag = osSetEventFromIsr(&netEvent);
565  }
566 
567  //System bus error?
568  if(events & ENET_EIR_EBERR_MASK)
569  {
570  //Disable EBERR interrupt
571  ENET1->EIMR &= ~ENET_EIMR_EBERR_MASK;
572 
573  //Set event flag
574  nicDriverInterface->nicEvent = TRUE;
575  //Notify the TCP/IP stack of the event
576  flag |= osSetEventFromIsr(&netEvent);
577  }
578 
579  //Leave interrupt service routine
580  osExitIsr(flag);
581 }
582 
583 
584 /**
585  * @brief i.MX6UL Ethernet MAC event handler
586  * @param[in] interface Underlying network interface
587  **/
588 
590 {
591  error_t error;
592  uint32_t status;
593 
594  //Read interrupt event register
595  status = ENET1->EIR;
596 
597  //Packet received?
598  if(status & ENET_EIR_RXF_MASK)
599  {
600  //Clear RXF interrupt flag
601  ENET1->EIR = ENET_EIR_RXF_MASK;
602 
603  //Process all pending packets
604  do
605  {
606  //Read incoming packet
607  error = mcimx6ulEth1ReceivePacket(interface);
608 
609  //No more data in the receive buffer?
610  } while(error != ERROR_BUFFER_EMPTY);
611  }
612 
613  //System bus error?
614  if(status & ENET_EIR_EBERR_MASK)
615  {
616  //Clear EBERR interrupt flag
617  ENET1->EIR = ENET_EIR_EBERR_MASK;
618 
619  //Disable Ethernet MAC
620  ENET1->ECR &= ~ENET_ECR_ETHEREN_MASK;
621  //Reset buffer descriptors
622  mcimx6ulEth1InitBufferDesc(interface);
623  //Resume normal operation
624  ENET1->ECR |= ENET_ECR_ETHEREN_MASK;
625  //Instruct the DMA to poll the receive descriptor list
626  ENET1->RDAR = ENET_RDAR_RDAR_MASK;
627  }
628 
629  //Re-enable Ethernet MAC interrupts
630  ENET1->EIMR = ENET_EIMR_TXF_MASK | ENET_EIMR_RXF_MASK | ENET_EIMR_EBERR_MASK;
631 }
632 
633 
634 /**
635  * @brief Send a packet
636  * @param[in] interface Underlying network interface
637  * @param[in] buffer Multi-part buffer containing the data to send
638  * @param[in] offset Offset to the first data byte
639  * @return Error code
640  **/
641 
643  const NetBuffer *buffer, size_t offset)
644 {
645  static uint8_t temp[MCIMX6UL_ETH1_TX_BUFFER_SIZE];
646  size_t length;
647 
648  //Retrieve the length of the packet
649  length = netBufferGetLength(buffer) - offset;
650 
651  //Check the frame length
653  {
654  //The transmitter can accept another packet
655  osSetEvent(&interface->nicTxEvent);
656  //Report an error
657  return ERROR_INVALID_LENGTH;
658  }
659 
660  //Make sure the current buffer is available for writing
661  if(txBufferDesc[txBufferIndex][0] & ENET_TBD0_R)
662  return ERROR_FAILURE;
663 
664  //Copy user data to the transmit buffer
665  netBufferRead(temp, buffer, offset, length);
666  memcpy(txBuffer[txBufferIndex], temp, (length + 3) & ~3UL);
667 
668  //Clear BDU flag
669  txBufferDesc[txBufferIndex][4] = 0;
670 
671  //Check current index
672  if(txBufferIndex < (MCIMX6UL_ETH1_TX_BUFFER_COUNT - 1))
673  {
674  //Give the ownership of the descriptor to the DMA engine
675  txBufferDesc[txBufferIndex][0] = ENET_TBD0_R | ENET_TBD0_L |
677 
678  //Point to the next buffer
679  txBufferIndex++;
680  }
681  else
682  {
683  //Give the ownership of the descriptor to the DMA engine
684  txBufferDesc[txBufferIndex][0] = ENET_TBD0_R | ENET_TBD0_W |
686 
687  //Wrap around
688  txBufferIndex = 0;
689  }
690 
691  //Data synchronization barrier
692  __DSB();
693 
694  //Instruct the DMA to poll the transmit descriptor list
695  ENET1->TDAR = ENET_TDAR_TDAR_MASK;
696 
697  //Check whether the next buffer is available for writing
698  if(!(txBufferDesc[txBufferIndex][0] & ENET_TBD0_R))
699  {
700  //The transmitter can accept another packet
701  osSetEvent(&interface->nicTxEvent);
702  }
703 
704  //Successful processing
705  return NO_ERROR;
706 }
707 
708 
709 /**
710  * @brief Receive a packet
711  * @param[in] interface Underlying network interface
712  * @return Error code
713  **/
714 
716 {
717  static uint8_t temp[MCIMX6UL_ETH1_RX_BUFFER_SIZE];
718  error_t error;
719  size_t n;
720 
721  //Make sure the current buffer is available for reading
722  if(!(rxBufferDesc[rxBufferIndex][0] & ENET_RBD0_E))
723  {
724  //The frame should not span multiple buffers
725  if(rxBufferDesc[rxBufferIndex][0] & ENET_RBD0_L)
726  {
727  //Check whether an error occurred
728  if(!(rxBufferDesc[rxBufferIndex][0] & (ENET_RBD0_LG |
730  {
731  //Retrieve the length of the frame
732  n = rxBufferDesc[rxBufferIndex][0] & ENET_RBD0_DATA_LENGTH;
733  //Limit the number of data to read
735 
736  //Copy data from the receive buffer
737  memcpy(temp, rxBuffer[rxBufferIndex], (n + 3) & ~3UL);
738 
739  //Pass the packet to the upper layer
740  nicProcessPacket(interface, temp, n);
741 
742  //Valid packet received
743  error = NO_ERROR;
744  }
745  else
746  {
747  //The received packet contains an error
748  error = ERROR_INVALID_PACKET;
749  }
750  }
751  else
752  {
753  //The packet is not valid
754  error = ERROR_INVALID_PACKET;
755  }
756 
757  //Clear BDU flag
758  rxBufferDesc[rxBufferIndex][4] = 0;
759 
760  //Check current index
761  if(rxBufferIndex < (MCIMX6UL_ETH1_RX_BUFFER_COUNT - 1))
762  {
763  //Give the ownership of the descriptor back to the DMA engine
764  rxBufferDesc[rxBufferIndex][0] = ENET_RBD0_E;
765  //Point to the next buffer
766  rxBufferIndex++;
767  }
768  else
769  {
770  //Give the ownership of the descriptor back to the DMA engine
771  rxBufferDesc[rxBufferIndex][0] = ENET_RBD0_E | ENET_RBD0_W;
772  //Wrap around
773  rxBufferIndex = 0;
774  }
775 
776  //Instruct the DMA to poll the receive descriptor list
777  ENET1->RDAR = ENET_RDAR_RDAR_MASK;
778  }
779  else
780  {
781  //No more data in the receive buffer
782  error = ERROR_BUFFER_EMPTY;
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  uint32_t crc;
801  uint32_t unicastHashTable[2];
802  uint32_t multicastHashTable[2];
803  MacFilterEntry *entry;
804 
805  //Debug message
806  TRACE_DEBUG("Updating MAC filter...\r\n");
807 
808  //Clear hash table (unicast address filtering)
809  unicastHashTable[0] = 0;
810  unicastHashTable[1] = 0;
811 
812  //Clear hash table (multicast address filtering)
813  multicastHashTable[0] = 0;
814  multicastHashTable[1] = 0;
815 
816  //The MAC address filter contains the list of MAC addresses to accept
817  //when receiving an Ethernet frame
818  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
819  {
820  //Point to the current entry
821  entry = &interface->macAddrFilter[i];
822 
823  //Valid entry?
824  if(entry->refCount > 0)
825  {
826  //Compute CRC over the current MAC address
827  crc = mcimx6ulEth1CalcCrc(&entry->addr, sizeof(MacAddr));
828 
829  //The upper 6 bits in the CRC register are used to index the
830  //contents of the hash table
831  k = (crc >> 26) & 0x3F;
832 
833  //Multicast address?
834  if(macIsMulticastAddr(&entry->addr))
835  {
836  //Update the multicast hash table
837  multicastHashTable[k / 32] |= (1 << (k % 32));
838  }
839  else
840  {
841  //Update the unicast hash table
842  unicastHashTable[k / 32] |= (1 << (k % 32));
843  }
844  }
845  }
846 
847  //Write the hash table (unicast address filtering)
848  ENET1->IALR = unicastHashTable[0];
849  ENET1->IAUR = unicastHashTable[1];
850 
851  //Write the hash table (multicast address filtering)
852  ENET1->GALR = multicastHashTable[0];
853  ENET1->GAUR = multicastHashTable[1];
854 
855  //Debug message
856  TRACE_DEBUG(" IALR = %08" PRIX32 "\r\n", ENET1->IALR);
857  TRACE_DEBUG(" IAUR = %08" PRIX32 "\r\n", ENET1->IAUR);
858  TRACE_DEBUG(" GALR = %08" PRIX32 "\r\n", ENET1->GALR);
859  TRACE_DEBUG(" GAUR = %08" PRIX32 "\r\n", ENET1->GAUR);
860 
861  //Successful processing
862  return NO_ERROR;
863 }
864 
865 
866 /**
867  * @brief Adjust MAC configuration parameters for proper operation
868  * @param[in] interface Underlying network interface
869  * @return Error code
870  **/
871 
873 {
874  //Disable Ethernet MAC while modifying configuration registers
875  ENET1->ECR &= ~ENET_ECR_ETHEREN_MASK;
876 
877  //10BASE-T or 100BASE-TX operation mode?
878  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
879  {
880  //100 Mbps operation
881  ENET1->RCR &= ~ENET_RCR_RMII_10T_MASK;
882  }
883  else
884  {
885  //10 Mbps operation
886  ENET1->RCR |= ENET_RCR_RMII_10T_MASK;
887  }
888 
889  //Half-duplex or full-duplex mode?
890  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
891  {
892  //Full-duplex mode
893  ENET1->TCR |= ENET_TCR_FDEN_MASK;
894  //Receive path operates independently of transmit
895  ENET1->RCR &= ~ENET_RCR_DRT_MASK;
896  }
897  else
898  {
899  //Half-duplex mode
900  ENET1->TCR &= ~ENET_TCR_FDEN_MASK;
901  //Disable reception of frames while transmitting
902  ENET1->RCR |= ENET_RCR_DRT_MASK;
903  }
904 
905  //Reset buffer descriptors
906  mcimx6ulEth1InitBufferDesc(interface);
907 
908  //Re-enable Ethernet MAC
909  ENET1->ECR |= ENET_ECR_ETHEREN_MASK;
910  //Instruct the DMA to poll the receive descriptor list
911  ENET1->RDAR = ENET_RDAR_RDAR_MASK;
912 
913  //Successful processing
914  return NO_ERROR;
915 }
916 
917 
918 /**
919  * @brief Write PHY register
920  * @param[in] phyAddr PHY address
921  * @param[in] regAddr Register address
922  * @param[in] data Register value
923  **/
924 
925 void mcimx6ulEth1WritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
926 {
927  uint32_t value;
928 
929  //Set up a write operation
930  value = ENET_MMFR_ST(1) | ENET_MMFR_OP(1) | ENET_MMFR_TA(2);
931  //PHY address
932  value |= ENET_MMFR_PA(phyAddr);
933  //Register address
934  value |= ENET_MMFR_RA(regAddr);
935  //Register value
936  value |= ENET_MMFR_DATA(data);
937 
938  //Clear MII interrupt flag
939  ENET1->EIR = ENET_EIR_MII_MASK;
940  //Start a write operation
941  ENET1->MMFR = value;
942  //Wait for the write to complete
943  while(!(ENET1->EIR & ENET_EIR_MII_MASK));
944 }
945 
946 
947 /**
948  * @brief Read PHY register
949  * @param[in] phyAddr PHY address
950  * @param[in] regAddr Register address
951  * @return Register value
952  **/
953 
954 uint16_t mcimx6ulEth1ReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
955 {
956  uint32_t value;
957 
958  //Set up a read operation
959  value = ENET_MMFR_ST(1) | ENET_MMFR_OP(2) | ENET_MMFR_TA(2);
960  //PHY address
961  value |= ENET_MMFR_PA(phyAddr);
962  //Register address
963  value |= ENET_MMFR_RA(regAddr);
964 
965  //Clear MII interrupt flag
966  ENET1->EIR = ENET_EIR_MII_MASK;
967  //Start a read operation
968  ENET1->MMFR = value;
969  //Wait for the read to complete
970  while(!(ENET1->EIR & ENET_EIR_MII_MASK));
971 
972  //Return PHY register contents
973  return ENET1->MMFR & ENET_MMFR_DATA_MASK;
974 }
975 
976 
977 /**
978  * @brief CRC calculation
979  * @param[in] data Pointer to the data over which to calculate the CRC
980  * @param[in] length Number of bytes to process
981  * @return Resulting CRC value
982  **/
983 
984 uint32_t mcimx6ulEth1CalcCrc(const void *data, size_t length)
985 {
986  uint_t i;
987  uint_t j;
988 
989  //Point to the data over which to calculate the CRC
990  const uint8_t *p = (uint8_t *) data;
991  //CRC preset value
992  uint32_t crc = 0xFFFFFFFF;
993 
994  //Loop through data
995  for(i = 0; i < length; i++)
996  {
997  //Update CRC value
998  crc ^= p[i];
999  //The message is processed bit by bit
1000  for(j = 0; j < 8; j++)
1001  {
1002  if(crc & 0x00000001)
1003  crc = (crc >> 1) ^ 0xEDB88320;
1004  else
1005  crc = crc >> 1;
1006  }
1007  }
1008 
1009  //Return CRC value
1010  return crc;
1011 }
#define MCIMX6UL_ETH1_TX_BUFFER_COUNT
MacAddr addr
MAC address.
Definition: ethernet.h:219
#define ENET_RBD0_L
#define ENET_RBD0_W
error_t mcimx6ulEth1SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
#define ENET_RBD0_OV
TCP/IP stack core.
Debugging facilities.
uint8_t p
Definition: ndp.h:297
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MCIMX6UL_ETH1_RX_BUFFER_COUNT
Generic error code.
Definition: error.h:45
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:107
#define ENET_TBD2_INT
#define MCIMX6UL_ETH1_RX_BUFFER_SIZE
#define txBuffer
i.MX6UL Ethernet MAC controller (ENET1 instance)
const NicDriver mcimx6ulEth1Driver
i.MX6UL Ethernet MAC driver
#define ENET_RBD0_LG
error_t mcimx6ulEth1UpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define TRUE
Definition: os_port.h:50
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:74
#define ENET_RBD0_E
void mcimx6ulEth1WritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
error_t mcimx6ulEth1UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define ENET_TBD0_R
#define ENET_RBD0_NO
void mcimx6ulEth1EnableIrq(NetInterface *interface)
Enable interrupts.
#define MCIMX6UL_ETH1_IRQ_PRIORITY
void mcimx6ulEth1InitBufferDesc(NetInterface *interface)
Initialize buffer descriptors.
#define ENET_TBD0_DATA_LENGTH
#define ENET_RBD0_CR
void mcimx6ulEth1DisableIrq(NetInterface *interface)
Disable interrupts.
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
NIC driver.
Definition: nic.h:164
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define MIN(a, b)
Definition: os_port.h:62
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define TRACE_INFO(...)
Definition: debug.h:94
#define ENET_TBD0_TC
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:91
Ethernet interface.
Definition: nic.h:71
#define ENET_RBD2_INT
Success.
Definition: error.h:44
#define rxBuffer
Ipv6Addr address
OsEvent netEvent
Definition: net.c:73
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:220
#define ENET_RBD0_DATA_LENGTH
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t
Error codes.
Definition: error.h:42
unsigned int uint_t
Definition: compiler_port.h:45
__start_packed struct @112 MacAddr
MAC address.
uint8_t data[]
Definition: dtls_misc.h:169
#define NetInterface
Definition: net.h:36
uint16_t mcimx6ulEth1ReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
uint8_t value[]
Definition: dtls_misc.h:143
void mcimx6ulEth1InitGpio(NetInterface *interface)
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
error_t mcimx6ulEth1ReceivePacket(NetInterface *interface)
Receive a packet.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:395
#define MCIMX6UL_ETH1_TX_BUFFER_SIZE
void mcimx6ulEth1EventHandler(NetInterface *interface)
i.MX6UL Ethernet MAC event handler
uint32_t mcimx6ulEth1CalcCrc(const void *data, size_t length)
CRC calculation.
#define osExitIsr(flag)
#define osEnterIsr()
void mcimx6ulEth1Tick(NetInterface *interface)
i.MX6UL Ethernet MAC timer handler
error_t mcimx6ulEth1Init(NetInterface *interface)
i.MX6UL Ethernet MAC initialization
#define ENET_TBD0_L
uint8_t length
Definition: dtls_misc.h:142
uint8_t n
void ENET1_DriverIRQHandler(uint32_t giccIar, void *userParam)
Ethernet MAC interrupt (ENET1 instance)
#define ENET_TBD0_W
#define ENET_RBD0_TR
#define FALSE
Definition: os_port.h:46
int bool_t
Definition: compiler_port.h:49
MAC filter table entry.
Definition: ethernet.h:217
#define TRACE_DEBUG(...)
Definition: debug.h:106