am64x_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file am64x_eth_driver.c
3  * @brief AM64x Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include <hw_include/csl_cpswitch.h>
36 #include <kernel/dpl/AddrTranslateP.h>
37 #include <drivers/pinmux.h>
38 #include <drivers/udma/udma_priv.h>
39 #include <networking/enet/utils/include/enet_apputils.h>
40 #include <networking/enet/utils/include/enet_appmemutils.h>
41 #include <networking/enet/utils/include/enet_appmemutils_cfg.h>
42 #include "core/net.h"
44 #include "debug.h"
45 
46 //MDIO input clock frequency
47 #define MDIO_INPUT_CLK 250000000
48 //MDIO output clock frequency
49 #define MDIO_OUTPUT_CLK 1000000
50 
51 //Underlying network interface (port 1)
52 static NetInterface *nicDriverInterface1 = NULL;
53 //Underlying network interface (port 2)
54 static NetInterface *nicDriverInterface2 = NULL;
55 
56 //TX DMA handle
57 static EnetDma_TxChHandle txChHandle = NULL;
58 //RX DMA handle
59 static EnetDma_RxChHandle rxChHandle = NULL;
60 
61 //TX packet queue
62 static EnetDma_PktQ txFreePacketQueue;
63 //RX packet queue
64 static EnetDma_PktQ rxFreePacketQueue;
65 
66 
67 /**
68  * @brief AM64x Ethernet MAC driver (port1)
69  **/
70 
72 {
74  ETH_MTU,
85  FALSE,
86  TRUE,
87  TRUE,
88  FALSE
89 };
90 
91 
92 /**
93  * @brief AM64x Ethernet MAC driver (port2)
94  **/
95 
97 {
99  ETH_MTU,
101  am64xEthTick,
110  FALSE,
111  TRUE,
112  TRUE,
113  FALSE
114 };
115 
116 
117 /**
118  * @brief AM64x Ethernet MAC initialization (port 1)
119  * @param[in] interface Underlying network interface
120  * @return Error code
121  **/
122 
124 {
125  error_t error;
126  uint32_t temp;
127  volatile CSL_Xge_cpswRegs *ctrlRegs;
128  volatile CSL_AleRegs *aleRegs;
129  volatile CSL_main_ctrl_mmr_cfg0Regs *mmrRegs;
130 
131  //Debug message
132  TRACE_INFO("Initializing AM64x Ethernet MAC (port 1)...\r\n");
133 
134  //Initialize CPSW instance
135  am64xEthInitInstance(interface);
136 
137  //Save underlying network interface
138  nicDriverInterface1 = interface;
139 
140  //PHY transceiver initialization
141  error = interface->phyDriver->init(interface);
142  //Any error to report?
143  if(error)
144  {
145  return error;
146  }
147 
148  //Unspecified MAC address?
149  if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
150  {
151  //Point to the CTRL_MMR0 registers
152  mmrRegs = (volatile CSL_main_ctrl_mmr_cfg0Regs *) CSL_CTRL_MMR0_CFG0_BASE;
153 
154  //Use the factory preprogrammed MAC address
155  interface->macAddr.b[0] = (mmrRegs->MAC_ID1 >> 8) & 0xFF;
156  interface->macAddr.b[1] = mmrRegs->MAC_ID1 & 0xFF;
157  interface->macAddr.b[2] = (mmrRegs->MAC_ID0 >> 24) & 0xFF;
158  interface->macAddr.b[3] = (mmrRegs->MAC_ID0 >> 16) & 0xFF;
159  interface->macAddr.b[4] = (mmrRegs->MAC_ID0 >> 8) & 0xFF;
160  interface->macAddr.b[5] = mmrRegs->MAC_ID0 & 0xFF;
161 
162  //Generate the 64-bit interface identifier
163  macAddrToEui64(&interface->macAddr, &interface->eui64);
164  }
165 
166  //Point to the CPSW0_CONTROL registers
167  ctrlRegs = (volatile CSL_Xge_cpswRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_NU_OFFSET);
168  //Point to the CPSW0_ALE registers
169  aleRegs = (volatile CSL_AleRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_ALE_OFFSET);
170 
171  //Set CMD_IDLE bit to 1 in the port control register
172  ctrlRegs->ENETPORT[0].PN_MAC_CONTROL_REG |= CSL_XGE_CPSW_PN_MAC_CONTROL_REG_CMD_IDLE_MASK;
173 
174  //Wait for IDLE bit to be set to 1 in the port status register
175  while((ctrlRegs->ENETPORT[0].PN_MAC_STATUS_REG & CSL_XGE_CPSW_PN_MAC_STATUS_REG_IDLE_MASK) == 0)
176  {
177  }
178 
179  //Set SOFT_RESET bit to 1 in the port software reset register
180  ctrlRegs->ENETPORT[0].PN_MAC_SOFT_RESET_REG |= CSL_XGE_CPSW_PN_MAC_SOFT_RESET_REG_SOFT_RESET_MASK;
181 
182  //Wait for SOFT_RESET bit to be cleared to confirm reset completion
183  while((ctrlRegs->ENETPORT[0].PN_MAC_SOFT_RESET_REG &
184  CSL_XGE_CPSW_PN_MAC_SOFT_RESET_REG_SOFT_RESET_MASK) != 0)
185  {
186  }
187 
188  //Set port state (forwarding)
189  temp = aleRegs->I0_ALE_PORTCTL0[1] & ~CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_MASK;
190  aleRegs->I0_ALE_PORTCTL0[1] = temp | (3 << CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_SHIFT);
191 
192  //Set the MAC address of the station
193  ctrlRegs->ENETPORT[0].PN_SA_H_REG = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
194  ctrlRegs->ENETPORT[0].PN_SA_L_REG = interface->macAddr.w[2];
195 
196  //Configure VLAN identifier and VLAN priority
197  ctrlRegs->ENETPORT[0].PN_PORT_VLAN_REG = (0 << CSL_XGE_CPSW_PN_PORT_VLAN_REG_PORT_PRI_SHIFT) |
198  (CPSW_PORT1 << CSL_XGE_CPSW_PN_PORT_VLAN_REG_PORT_VID_SHIFT);
199 
200  //Add a VLAN entry in the ALE table
202 
203  //Add a VLAN/unicast address entry in the ALE table
204  am64xEthAddVlanAddrEntry(CPSW_PORT1, CPSW_PORT1, &interface->macAddr);
205 
206  //Enable CPSW statistics
207  ctrlRegs->STAT_PORT_EN_REG |= CSL_XGE_CPSW_STAT_PORT_EN_REG_P1_STAT_EN_MASK;
208 
209  //Enable TX and RX
210  ctrlRegs->ENETPORT[0].PN_MAC_CONTROL_REG = CSL_XGE_CPSW_PN_MAC_CONTROL_REG_GMII_EN_MASK;
211 
212  //Accept any packets from the upper layer
213  osSetEvent(&interface->nicTxEvent);
214 
215  //Successful initialization
216  return NO_ERROR;
217 }
218 
219 
220 /**
221  * @brief AM64x Ethernet MAC initialization (port 2)
222  * @param[in] interface Underlying network interface
223  * @return Error code
224  **/
225 
227 {
228  error_t error;
229  uint32_t temp;
230  volatile CSL_Xge_cpswRegs *ctrlRegs;
231  volatile CSL_AleRegs *aleRegs;
232 
233  //Debug message
234  TRACE_INFO("Initializing AM64x Ethernet MAC (port 2)...\r\n");
235 
236  //Initialize CPSW instance
237  am64xEthInitInstance(interface);
238 
239  //Save underlying network interface
240  nicDriverInterface2 = interface;
241 
242  //PHY transceiver initialization
243  error = interface->phyDriver->init(interface);
244  //Any error to report?
245  if(error)
246  {
247  return error;
248  }
249 
250  //Point to the CPSW0_CONTROL registers
251  ctrlRegs = (volatile CSL_Xge_cpswRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_NU_OFFSET);
252  //Point to the CPSW0_ALE registers
253  aleRegs = (volatile CSL_AleRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_ALE_OFFSET);
254 
255  //Set CMD_IDLE bit to 1 in the port control register
256  ctrlRegs->ENETPORT[1].PN_MAC_CONTROL_REG |= CSL_XGE_CPSW_PN_MAC_CONTROL_REG_CMD_IDLE_MASK;
257 
258  //Wait for IDLE bit to be set to 1 in the port status register
259  while((ctrlRegs->ENETPORT[1].PN_MAC_STATUS_REG & CSL_XGE_CPSW_PN_MAC_STATUS_REG_IDLE_MASK) == 0)
260  {
261  }
262 
263  //Set SOFT_RESET bit to 1 in the port software reset register
264  ctrlRegs->ENETPORT[1].PN_MAC_SOFT_RESET_REG |= CSL_XGE_CPSW_PN_MAC_SOFT_RESET_REG_SOFT_RESET_MASK;
265 
266  //Wait for SOFT_RESET bit to be cleared to confirm reset completion
267  while((ctrlRegs->ENETPORT[1].PN_MAC_SOFT_RESET_REG &
268  CSL_XGE_CPSW_PN_MAC_SOFT_RESET_REG_SOFT_RESET_MASK) != 0)
269  {
270  }
271 
272  //Set port state (forwarding)
273  temp = aleRegs->I0_ALE_PORTCTL0[2] & ~CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_MASK;
274  aleRegs->I0_ALE_PORTCTL0[2] = temp | (3 << CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_SHIFT);
275 
276  //Set the MAC address of the station
277  ctrlRegs->ENETPORT[1].PN_SA_H_REG = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
278  ctrlRegs->ENETPORT[1].PN_SA_L_REG = interface->macAddr.w[2];
279 
280  //Configure VLAN identifier and VLAN priority
281  ctrlRegs->ENETPORT[1].PN_PORT_VLAN_REG = (0 << CSL_XGE_CPSW_PN_PORT_VLAN_REG_PORT_PRI_SHIFT) |
282  (CPSW_PORT2 << CSL_XGE_CPSW_PN_PORT_VLAN_REG_PORT_VID_SHIFT);
283 
284  //Add a VLAN entry in the ALE table
286 
287  //Add a VLAN/unicast address entry in the ALE table
288  am64xEthAddVlanAddrEntry(CPSW_PORT2, CPSW_PORT2, &interface->macAddr);
289 
290  //Enable CPSW statistics
291  ctrlRegs->STAT_PORT_EN_REG |= CSL_XGE_CPSW_STAT_PORT_EN_REG_P2_STAT_EN_MASK;
292 
293  //Enable TX and RX
294  ctrlRegs->ENETPORT[1].PN_MAC_CONTROL_REG = CSL_XGE_CPSW_PN_MAC_CONTROL_REG_GMII_EN_MASK;
295 
296  //Accept any packets from the upper layer
297  osSetEvent(&interface->nicTxEvent);
298 
299  //Successful initialization
300  return NO_ERROR;
301 }
302 
303 
304 /**
305  * @brief Initialize CPSW instance
306  * @param[in] interface Underlying network interface
307  **/
308 
310 {
311  int32_t status;
312  uint32_t i;
313  uint32_t temp;
314  uint32_t coreId;
315  uint32_t coreKey;
316  Cpsw_Cfg cpswConfig;
317  EnetOsal_Cfg osalConfig;
318  EnetUtils_Cfg utilsConfig;
319  EnetUdma_Cfg dmaConfig;
320  EnetUdma_OpenTxChPrms txChCfg;
321  EnetUdma_OpenRxFlowPrms rxChCfg;
322  Enet_IoctlPrms ioctlParams;
323  EnetPer_AttachCoreOutArgs attachCoreOutArgs;
324  Enet_Handle enetHandle;
325  Udma_DrvHandle udmaHandle;
326  EnetDma_Pkt *packetInfo;
327  volatile CSL_Xge_cpswRegs *ctrlRegs;
328  volatile CSL_AleRegs *aleRegs;
329  volatile CSL_MdioRegs *mdioRegs;
330  uint8_t macAddr[ENET_MAC_ADDR_LEN];
331 
332  //Initialization sequence is performed once
333  if(nicDriverInterface1 == NULL && nicDriverInterface2 == NULL)
334  {
335  uint32_t txChNum = 0;
336  uint32_t rxFlowIdx = 0;
337  uint32_t rxStartFlowIdx = 0;
338 
339  //Retrieve core ID
340  coreId = EnetSoc_getCoreId();
341 
342  //Select the interface mode (MII/RMII/RGMII) and configure pin muxing
343  am64xEthInitGpio(interface);
344 
345  //Initialize configuration structures
346  memset(&cpswConfig, 0, sizeof(Cpsw_Cfg));
347  memset(&dmaConfig, 0, sizeof(EnetUdma_Cfg));
348 
349  //Initialize OS abstraction layer
350  Enet_initOsalCfg(&osalConfig);
351  Enet_initUtilsCfg(&utilsConfig);
352  Enet_init(&osalConfig, &utilsConfig);
353 
354  //Debug message
355  TRACE_INFO(" Initializing memory...\r\n");
356 
357  //Initialize memory
358  status = EnetMem_init();
359  //Check status code
360  if(status != ENET_SOK)
361  {
362  //Debug message
363  TRACE_ERROR("Failed to initialize memory (status = %d)\r\n", status);
364  //Fatal error
365  EnetAppUtils_assert(false);
366  }
367 
368  //Initialize packet queue for free TX packets
369  EnetQueue_initQ(&txFreePacketQueue);
370 
371  //Debug message
372  TRACE_INFO(" Initializing UDMA driver...\r\n");
373 
374  //Open UDMA driver
375  udmaHandle = EnetAppUtils_udmaOpen(ENET_CPSW_3G, NULL);
376  //Invalid handle?
377  if(udmaHandle == NULL)
378  {
379  //Debug message
380  TRACE_ERROR("Failed to open UDMA driver\r\n");
381  //Fatal error
382  EnetAppUtils_assert(false);
383  }
384 
385  //Debug message
386  TRACE_INFO(" Initializing CPSW clocks...\r\n");
387  //Enable CPSW peripheral clocks
388  EnetAppUtils_enableClocks(ENET_CPSW_3G, 0);
389 
390  //Initialize DMA configuration
391  dmaConfig.rxChInitPrms.dmaPriority = UDMA_DEFAULT_RX_CH_DMA_PRIORITY;
392  dmaConfig.hUdmaDrv = udmaHandle;
393 
394  //Set CPSW parameters
395  Enet_initCfg(ENET_CPSW_3G, 0, &cpswConfig, sizeof(Cpsw_Cfg));
396  cpswConfig.vlanCfg.vlanAware = false;
397  cpswConfig.hostPortCfg.removeCrc = false;
398  cpswConfig.hostPortCfg.padShortPacket = true;
399  cpswConfig.hostPortCfg.passCrcErrors = false;
400  cpswConfig.dmaCfg = &dmaConfig;
401 
402  //Debug message
403  TRACE_INFO(" Initializing RM configuration...\r\n");
404  //Initialize RM configuration
405  EnetAppUtils_initResourceConfig(ENET_CPSW_3G, coreId, &cpswConfig.resCfg);
406 
407  //Debug message
408  TRACE_INFO(" Initializing CPSW peripheral...\r\n");
409 
410  //Open CPSW peripheral
411  enetHandle = Enet_open(ENET_CPSW_3G, 0, &cpswConfig, sizeof(Cpsw_Cfg));
412  //Invalid handle?
413  if(enetHandle == NULL)
414  {
415  //Debug message
416  TRACE_ERROR("Failed to open CPSW peripheral\r\n");
417  //Fatal error
418  EnetAppUtils_assert(false);
419  }
420 
421  //Debug message
422  TRACE_INFO(" Attaching core with RM...\r\n");
423 
424  //Set IOCTL parameters
425  ENET_IOCTL_SET_INOUT_ARGS(&ioctlParams, &coreId, &attachCoreOutArgs);
426 
427  //Attach the core with RM
428  status = Enet_ioctl(enetHandle, coreId, ENET_PER_IOCTL_ATTACH_CORE,
429  &ioctlParams);
430  //Check status code
431  if(status != ENET_SOK)
432  {
433  //Debug message
434  TRACE_ERROR("Failed to attach core with RM (status = %d)\r\n", status);
435  //Fatal error
436  EnetAppUtils_assert(false);
437  }
438 
439  //Save core key
440  coreKey = attachCoreOutArgs.coreKey;
441 
442  //Set DMA TX channel parameters
443  EnetDma_initTxChParams(&txChCfg);
444  txChCfg.hUdmaDrv = udmaHandle;
445  txChCfg.notifyCb = NULL;
446  txChCfg.cbArg = NULL;
447  txChCfg.useGlobalEvt = true;
448 
449  //Use default common parameters
450  EnetAppUtils_setCommonTxChPrms(&txChCfg);
451 
452  //Debug message
453  TRACE_INFO(" Opening DMA TX channel...\r\n");
454 
455  //Open the DMA TX channel
456  EnetAppUtils_openTxCh(enetHandle, coreKey, coreId, &txChNum,
457  &txChHandle, &txChCfg);
458  //Invalid handle?
459  if(txChHandle == NULL)
460  {
461  //Debug message
462  TRACE_ERROR("Failed to open DMA TX channel\r\n");
463  //Fatal error
464  EnetAppUtils_assert(false);
465  }
466 
467  //Allocate TX packet queue
468  for(i = 0; i < ENET_MEM_NUM_TX_PKTS; i++)
469  {
470  //Allocate a new packet
471  packetInfo = EnetMem_allocEthPkt(NULL, ENET_MEM_LARGE_POOL_PKT_SIZE,
472  ENETDMA_CACHELINE_ALIGNMENT);
473 
474  //Sanity check
475  EnetAppUtils_assert(packetInfo != NULL);
476 
477  //Add the packet to the queue
478  EnetQueue_enq(&txFreePacketQueue, &packetInfo->node);
479  }
480 
481  //Debug message
482  TRACE_INFO(" TX queue initialized with %u packets\r\n",
483  EnetQueue_getQCount(&txFreePacketQueue));
484 
485  //Set DMA TX channel parameters
486  EnetDma_initRxChParams(&rxChCfg);
487  rxChCfg.hUdmaDrv = udmaHandle;
488  rxChCfg.notifyCb = am64xEthRxIrqHandler;
489  rxChCfg.cbArg = NULL;
490  rxChCfg.useGlobalEvt = true;
491  rxChCfg.flowPrms.sizeThreshEn = 0;
492 
493  //Use default common parameters
494  EnetAppUtils_setCommonRxFlowPrms(&rxChCfg);
495 
496  //Open the DMA RX channel
497  EnetAppUtils_openRxFlowForChIdx(ENET_CPSW_3G, enetHandle, coreKey,
498  coreId, true, 0, &rxStartFlowIdx, &rxFlowIdx, macAddr, &rxChHandle,
499  &rxChCfg);
500  //Invalid handle?
501  if(rxChHandle == NULL)
502  {
503  //Debug message
504  TRACE_ERROR("Failed to open DMA RX channel\r\n");
505  //Fatal error
506  EnetAppUtils_assert(false);
507  }
508 
509  //Initialize RX packet queue
510  EnetQueue_initQ(&rxFreePacketQueue);
511 
512  //Allocate RX packet queue
513  for(i = 0; i < ENET_MEM_NUM_RX_PKTS; i++)
514  {
515  //Allocate a new packet
516  packetInfo = EnetMem_allocEthPkt(NULL, ENET_MEM_LARGE_POOL_PKT_SIZE,
517  ENETDMA_CACHELINE_ALIGNMENT);
518 
519  //Sanity check
520  EnetAppUtils_assert(packetInfo != NULL);
521 
522  //Add the packet to the queue
523  EnetQueue_enq(&rxFreePacketQueue, &packetInfo->node);
524  }
525 
526  //Debug message
527  TRACE_INFO(" RX queue initialized with %u packets\r\n",
528  EnetQueue_getQCount(&rxFreePacketQueue));
529 
530  //Submit all packets
531  EnetDma_submitRxPktQ(rxChHandle, &rxFreePacketQueue);
532 
533  //Point to the CPSW0_CONTROL registers
534  ctrlRegs = (volatile CSL_Xge_cpswRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_NU_OFFSET);
535  //Point to the CPSW0_ALE registers
536  aleRegs = (volatile CSL_AleRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_ALE_OFFSET);
537  //Point to the CPSW0_MDIO registers
538  mdioRegs = (volatile CSL_MdioRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_MDIO_OFFSET);
539 
540  //Enable ALE and clear ALE address table
541  aleRegs->ALE_CONTROL = CSL_ALE_ALE_CONTROL_ENABLE_ALE_MASK |
542  CSL_ALE_ALE_CONTROL_CLEAR_TABLE_MASK;
543 
544  //For dual MAC mode, configure VLAN aware mode
545  aleRegs->ALE_CONTROL |= CSL_ALE_ALE_CONTROL_ALE_VLAN_AWARE_MASK;
546 
547  //Set host port state (forwarding)
548  temp = aleRegs->I0_ALE_PORTCTL0[0] & ~CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_MASK;
549  aleRegs->I0_ALE_PORTCTL0[0] = temp | (3 << CSL_ALE_I0_ALE_PORTCTL0_I0_REG_P0_PORTSTATE_SHIFT);
550 
551  //Configure host port
552  ctrlRegs->P0_CONTROL_REG = 0;
553 
554  //Set the maximum frame length
555  temp = ctrlRegs->P0_RX_MAXLEN_REG & ~CSL_XGE_CPSW_P0_RX_MAXLEN_REG_RX_MAXLEN_MASK;
556  ctrlRegs->P0_RX_MAXLEN_REG = temp | (ETH_MAX_FRAME_SIZE << CSL_XGE_CPSW_P0_RX_MAXLEN_REG_RX_MAXLEN_SHIFT);
557 
558  //Enable host port
559  ctrlRegs->CONTROL_REG = CSL_XGE_CPSW_CONTROL_REG_P0_RX_PAD_MASK |
560  CSL_XGE_CPSW_CONTROL_REG_P0_ENABLE_MASK;
561 
562  //Enable CPSW statistics
563  ctrlRegs->STAT_PORT_EN_REG |= CSL_XGE_CPSW_STAT_PORT_EN_REG_P0_STAT_EN_MASK;
564 
565  //Calculate the MDC clock divider to be used
566  temp = (MDIO_INPUT_CLK / MDIO_OUTPUT_CLK) - 1;
567 
568  //Initialize MDIO interface
569  mdioRegs->CONTROL_REG = CSL_MDIO_CONTROL_REG_ENABLE_MASK |
570  CSL_MDIO_CONTROL_REG_FAULT_DETECT_ENABLE_MASK |
571  (temp & CSL_MDIO_CONTROL_REG_CLKDIV_MASK);
572  }
573 }
574 
575 
576 /**
577  * @brief GPIO configuration
578  * @param[in] interface Underlying network interface
579  **/
580 
581 __weak_func void am64xEthInitGpio(NetInterface *interface)
582 {
583 //TMDS64GPEVM evaluation board?
584 #if defined(USE_TMDS64GPEVM)
585  //MDIO/MDC pins
586  const Pinmux_PerCfg_t mdioPins[] =
587  {
588  //MDIO0_MDC (ball R2)
589  {PIN_PRG0_PRU1_GPO19, PIN_MODE(4) | PIN_PULL_DISABLE},
590  //MDIO0_MDIO (ball P5)
591  {PIN_PRG0_PRU1_GPO18, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
592 
593  //RGMII1_TXC (ball U14)
594  {PIN_PRG1_PRU0_GPO10, PIN_MODE(4) | PIN_PULL_DISABLE},
595  //RGMII1_TX_CTL (ball U15)
596  {PIN_PRG1_PRU0_GPO9, PIN_MODE(4) | PIN_PULL_DISABLE},
597  //RGMII1_TD0 (ball V15)
598  {PIN_PRG1_PRU1_GPO7, PIN_MODE(4) | PIN_PULL_DISABLE},
599  //RGMII1_TD1 (ball V14)
600  {PIN_PRG1_PRU1_GPO9, PIN_MODE(4) | PIN_PULL_DISABLE},
601  //RGMII1_TD2 (ball W14)
602  {PIN_PRG1_PRU1_GPO10, PIN_MODE(4) | PIN_PULL_DISABLE},
603  //RGMII1_TD3 (ball AA14)
604  {PIN_PRG1_PRU1_GPO17, PIN_MODE(4) | PIN_PULL_DISABLE},
605  //RGMII1_RXC (ball AA5)
606  {PIN_PRG0_PRU0_GPO10, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
607  //RGMII1_RX_CTL (ball W6)
608  {PIN_PRG0_PRU0_GPO9, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
609  //RGMII1_RD0 (ball W5)
610  {PIN_PRG0_PRU1_GPO7, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
611  //RGMII1_RD1 (ball Y5)
612  {PIN_PRG0_PRU1_GPO9, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
613  //RGMII1_RD2 (ball V6)
614  {PIN_PRG0_PRU1_GPO10, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
615  //RGMII1_RD3 (ball V5)
616  {PIN_PRG0_PRU1_GPO17, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
617 
618  //RGMII2_TXC (ball Y10)
619  {PIN_PRG1_PRU1_GPO16, PIN_MODE(4) | PIN_PULL_DISABLE},
620  //RGMII2_TX_CTL (ball Y11)
621  {PIN_PRG1_PRU1_GPO15, PIN_MODE(4) | PIN_PULL_DISABLE},
622  //RGMII2_TD0 (ball AA10)
623  {PIN_PRG1_PRU1_GPO11, PIN_MODE(4) | PIN_PULL_DISABLE},
624  //RGMII2_TD1 (ball V10)
625  {PIN_PRG1_PRU1_GPO12, PIN_MODE(4) | PIN_PULL_DISABLE},
626  //RGMII2_TD2 (ball U10)
627  {PIN_PRG1_PRU1_GPO13, PIN_MODE(4) | PIN_PULL_DISABLE},
628  //RGMII2_TD3 (ball AA11)
629  {PIN_PRG1_PRU1_GPO14, PIN_MODE(4) | PIN_PULL_DISABLE},
630  //RGMII2_RXC (ball U11)
631  {PIN_PRG1_PRU1_GPO6, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
632  //RGMII2_RX_CTL (ball W12)
633  {PIN_PRG1_PRU1_GPO4, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
634  //RGMII2_RD0 (ball W11)
635  {PIN_PRG1_PRU1_GPO0, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
636  //RGMII2_RD1 (ball V11)
637  {PIN_PRG1_PRU1_GPO1, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
638  //RGMII2_RD2 (ball AA12)
639  {PIN_PRG1_PRU1_GPO2, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
640  //RGMII2_RD3 (ball Y12)
641  {PIN_PRG1_PRU1_GPO3, PIN_MODE(4) | PIN_INPUT_ENABLE | PIN_PULL_DISABLE},
642 
643  //End marker
644  {PINMUX_END, PINMUX_END}
645  };
646 
647  //Configure MDIO/MDC pins
648  Pinmux_config(mdioPins, PINMUX_DOMAIN_ID_MAIN);
649 #endif
650 }
651 
652 
653 /**
654  * @brief AM64x Ethernet MAC timer handler
655  *
656  * This routine is periodically called by the TCP/IP stack to handle periodic
657  * operations such as polling the link state
658  *
659  * @param[in] interface Underlying network interface
660  **/
661 
662 void am64xEthTick(NetInterface *interface)
663 {
664  //Valid Ethernet PHY or switch driver?
665  if(interface->phyDriver != NULL)
666  {
667  //Handle periodic operations
668  interface->phyDriver->tick(interface);
669  }
670  else if(interface->switchDriver != NULL)
671  {
672  //Handle periodic operations
673  interface->switchDriver->tick(interface);
674  }
675  else
676  {
677  //Just for sanity
678  }
679 }
680 
681 
682 /**
683  * @brief Enable interrupts
684  * @param[in] interface Underlying network interface
685  **/
686 
688 {
689  //Valid Ethernet PHY or switch driver?
690  if(interface->phyDriver != NULL)
691  {
692  //Enable Ethernet PHY interrupts
693  interface->phyDriver->enableIrq(interface);
694  }
695  else if(interface->switchDriver != NULL)
696  {
697  //Enable Ethernet switch interrupts
698  interface->switchDriver->enableIrq(interface);
699  }
700  else
701  {
702  //Just for sanity
703  }
704 }
705 
706 
707 /**
708  * @brief Disable interrupts
709  * @param[in] interface Underlying network interface
710  **/
711 
713 {
714  //Valid Ethernet PHY or switch driver?
715  if(interface->phyDriver != NULL)
716  {
717  //Disable Ethernet PHY interrupts
718  interface->phyDriver->disableIrq(interface);
719  }
720  else if(interface->switchDriver != NULL)
721  {
722  //Disable Ethernet switch interrupts
723  interface->switchDriver->disableIrq(interface);
724  }
725  else
726  {
727  //Just for sanity
728  }
729 }
730 
731 
732 /**
733  * @brief AM64x Ethernet MAC receive interrupt
734  * @param[in] arg Unused parameter
735  **/
736 
737 void am64xEthRxIrqHandler(void *arg)
738 {
739  bool_t flag;
740 
741  //Interrupt service routine prologue
742  osEnterIsr();
743 
744  //Set event flag
745  nicDriverInterface1->nicEvent = TRUE;
746  //Notify the TCP/IP stack of the event
747  flag = osSetEventFromIsr(&netEvent);
748 
749  //Interrupt service routine epilogue
750  osExitIsr(flag);
751 }
752 
753 
754 /**
755  * @brief AM64x Ethernet MAC event handler
756  * @param[in] interface Underlying network interface
757  **/
758 
760 {
761  static uint32_t temp[ENET_MEM_LARGE_POOL_PKT_SIZE / 4];
762  size_t n;
763  int32_t status;
764  EnetDma_PktQ readyPacketQueue;
765  EnetDma_PktQ freePacketQueue;
766  EnetDma_Pkt *packetInfo;
767  NetRxAncillary ancillary;
768 
769  //Initialize packet queues
770  EnetQueue_initQ(&readyPacketQueue);
771  EnetQueue_initQ(&freePacketQueue);
772 
773  //Retrieve received packets
774  status = EnetDma_retrieveRxPktQ(rxChHandle, &readyPacketQueue);
775 
776  //Return status code
777  if(status == ENET_SOK)
778  {
779  //Get the first received packet
780  packetInfo = (EnetDma_Pkt *) EnetQueue_deq(&readyPacketQueue);
781 
782  //Consume the received packets and send them back
783  while(packetInfo != NULL)
784  {
785  //Check the port on which the packet was received
786  if(packetInfo->rxPortNum == ENET_MAC_PORT_1)
787  {
788  //Port 1
789  interface = nicDriverInterface1;
790  }
791  else if(packetInfo->rxPortNum == ENET_MAC_PORT_2)
792  {
793  //Port 2
794  interface = nicDriverInterface2;
795  }
796  else
797  {
798  //Invalid port
799  interface = NULL;
800  }
801 
802  //Retrieve the length of the frame
803  n = packetInfo->userBufLen;
804 
805  //Sanity check
806  if(interface != NULL)
807  {
808  //Copy data from the receive buffer
809  osMemcpy(temp, packetInfo->bufPtr, (n + 3) & ~3UL);
810 
811  //Additional options can be passed to the stack along with the packet
812  ancillary = NET_DEFAULT_RX_ANCILLARY;
813 
814  //Pass the packet to the upper layer
815  nicProcessPacket(interface, (uint8_t *) temp, n, &ancillary);
816  }
817 
818  //Restore buffer length
819  packetInfo->userBufLen = ENET_MEM_LARGE_POOL_PKT_SIZE;
820 
821  //Release the received packet
822  EnetQueue_enq(&freePacketQueue, &packetInfo->node);
823 
824  //Get the next received packet
825  packetInfo = (EnetDma_Pkt *) EnetQueue_deq(&readyPacketQueue);
826  }
827 
828  //Send the processed packets back to the RX queue
829  EnetDma_submitRxPktQ(rxChHandle, &freePacketQueue);
830  }
831 }
832 
833 
834 /**
835  * @brief Send a packet
836  * @param[in] interface Underlying network interface
837  * @param[in] buffer Multi-part buffer containing the data to send
838  * @param[in] offset Offset to the first data byte
839  * @param[in] ancillary Additional options passed to the stack along with
840  * the packet
841  * @return Error code
842  **/
843 
845  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
846 {
847  size_t length;
848  int32_t status;
849  EnetDma_PktQ freePacketQueue;
850  EnetDma_PktQ submitPacketQueue;
851  EnetDma_Pkt *packetInfo;
852 
853  //Initialize packet queues
854  EnetQueue_initQ(&freePacketQueue);
855  EnetQueue_initQ(&submitPacketQueue);
856 
857  //Retrieve free TX packets
858  status = EnetDma_retrieveTxPktQ(txChHandle, &freePacketQueue);
859 
860  //Return status code
861  if(status == ENET_SOK)
862  {
863  //Get the first free packet
864  packetInfo = (EnetDma_Pkt *) EnetQueue_deq(&freePacketQueue);
865 
866  //Move free packets to the queue
867  while(packetInfo != NULL)
868  {
869  EnetQueue_enq(&txFreePacketQueue, &packetInfo->node);
870  packetInfo = (EnetDma_Pkt *) EnetQueue_deq(&freePacketQueue);
871  }
872  }
873 
874  //Retrieve the length of the packet
875  length = netBufferGetLength(buffer) - offset;
876 
877  //Check the frame length
878  if(length > ENET_MEM_LARGE_POOL_PKT_SIZE)
879  {
880  //The transmitter can accept another packet
881  osSetEvent(&interface->nicTxEvent);
882  //Report an error
883  return ERROR_INVALID_LENGTH;
884  }
885 
886  //Dequeue a free packet from the queue
887  packetInfo = (EnetDma_Pkt *) EnetQueue_deq(&txFreePacketQueue);
888 
889  //Any packet available?
890  if(packetInfo != NULL)
891  {
892  //Copy user data to the transmit buffer
893  netBufferRead(packetInfo->bufPtr, buffer, offset, length);
894 
895  //Prepare an new packet
896  packetInfo->userBufLen = length;
897  packetInfo->appPriv = NULL;
898  packetInfo->tsInfo.enableHostTxTs = false;
899 
900  //Select the relevant port number
901  if(interface == nicDriverInterface1)
902  {
903  //Port 1
904  packetInfo->txPortNum = ENET_MAC_PORT_1;
905  }
906  else
907  {
908  //Port 2
909  packetInfo->txPortNum = ENET_MAC_PORT_2;
910  }
911 
912  //Enqueue the packet for transmission
913  EnetQueue_enq(&submitPacketQueue, &packetInfo->node);
914  }
915 
916  //Transmit all queued packets
917  status = EnetDma_submitTxPktQ(txChHandle, &submitPacketQueue);
918 
919  //The transmitter can accept another packet
920  osSetEvent(&interface->nicTxEvent);
921 
922  //Return status code
923  if(status == ENET_SOK)
924  {
925  return NO_ERROR;
926  }
927  else
928  {
929  return ERROR_FAILURE;
930  }
931 }
932 
933 
934 /**
935  * @brief Configure MAC address filtering
936  * @param[in] interface Underlying network interface
937  * @return Error code
938  **/
939 
941 {
942  uint_t i;
943  uint_t port;
944  MacFilterEntry *entry;
945 
946  //Debug message
947  TRACE_DEBUG("Updating AM64x ALE table...\r\n");
948 
949  //Select the relevant port number
950  if(interface == nicDriverInterface1)
951  {
952  port = CPSW_PORT1;
953  }
954  else if(interface == nicDriverInterface2)
955  {
956  port = CPSW_PORT2;
957  }
958  else
959  {
960  port = CPSW_PORT0;
961  }
962 
963  //The MAC address filter contains the list of MAC addresses to accept when
964  //receiving an Ethernet frame
965  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
966  {
967  //Point to the current entry
968  entry = &interface->macAddrFilter[i];
969 
970  //Check whether the ALE table should be updated for the current multicast
971  //address
972  if(!macCompAddr(&entry->addr, &MAC_UNSPECIFIED_ADDR))
973  {
974  if(entry->addFlag)
975  {
976  //Add VLAN/multicast address entry to the ALE table
978  }
979  else if(entry->deleteFlag)
980  {
981  //Remove VLAN/multicast address entry from the ALE table
983  }
984  }
985  }
986 
987  //Successful processing
988  return NO_ERROR;
989 }
990 
991 
992 /**
993  * @brief Adjust MAC configuration parameters for proper operation
994  * @param[in] interface Underlying network interface
995  * @return Error code
996  **/
997 
999 {
1000  uint32_t config = 0;
1001  volatile CSL_Xge_cpswRegs *ctrlRegs;
1002 
1003  //Point to the CPSW0_CONTROL registers
1004  ctrlRegs = (volatile CSL_Xge_cpswRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_NU_OFFSET);
1005 
1006  //Read MAC control register
1007  if(interface == nicDriverInterface1)
1008  {
1009  config = ctrlRegs->ENETPORT[0].PN_MAC_CONTROL_REG;
1010  }
1011  else if(interface == nicDriverInterface2)
1012  {
1013  config = ctrlRegs->ENETPORT[1].PN_MAC_CONTROL_REG;
1014  }
1015 
1016  //1000BASE-T operation mode?
1017  if(interface->linkSpeed == NIC_LINK_SPEED_1GBPS)
1018  {
1019  config |= CSL_XGE_CPSW_PN_MAC_CONTROL_REG_GIG_MASK;
1020  config &= ~CSL_XGE_CPSW_PN_MAC_CONTROL_REG_IFCTL_A_MASK;
1021  }
1022  //100BASE-TX operation mode?
1023  else if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
1024  {
1025  config &= ~CSL_XGE_CPSW_PN_MAC_CONTROL_REG_GIG_MASK;
1026  config |= CSL_XGE_CPSW_PN_MAC_CONTROL_REG_IFCTL_A_MASK;
1027  }
1028  //10BASE-T operation mode?
1029  else
1030  {
1031  config &= ~CSL_XGE_CPSW_PN_MAC_CONTROL_REG_GIG_MASK;
1032  config &= ~CSL_XGE_CPSW_PN_MAC_CONTROL_REG_IFCTL_A_MASK;
1033  }
1034 
1035  //Half-duplex or full-duplex mode?
1036  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
1037  {
1038  config |= CSL_XGE_CPSW_PN_MAC_CONTROL_REG_FULLDUPLEX_MASK;
1039  }
1040  else
1041  {
1042  config &= ~CSL_XGE_CPSW_PN_MAC_CONTROL_REG_FULLDUPLEX_MASK;
1043  }
1044 
1045  //Update MAC control register
1046  if(interface == nicDriverInterface1)
1047  {
1048  ctrlRegs->ENETPORT[0].PN_MAC_CONTROL_REG = config;
1049  }
1050  else if(interface == nicDriverInterface2)
1051  {
1052  ctrlRegs->ENETPORT[1].PN_MAC_CONTROL_REG = config;
1053  }
1054 
1055  //Successful processing
1056  return NO_ERROR;
1057 }
1058 
1059 
1060 /**
1061  * @brief Write PHY register
1062  * @param[in] opcode Access type (2 bits)
1063  * @param[in] phyAddr PHY address (5 bits)
1064  * @param[in] regAddr Register address (5 bits)
1065  * @param[in] data Register value
1066  **/
1067 
1068 void am64xEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
1069  uint8_t regAddr, uint16_t data)
1070 {
1071  uint32_t temp;
1072  volatile CSL_MdioRegs *mdioRegs;
1073 
1074  //Point to the CPSW0_MDIO registers
1075  mdioRegs = (volatile CSL_MdioRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_MDIO_OFFSET);
1076 
1077  //Valid opcode?
1078  if(opcode == SMI_OPCODE_WRITE)
1079  {
1080  //Set up a write operation
1081  temp = CSL_MDIO_USER_GROUP_USER_ACCESS_REG_GO_MASK |
1082  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_WRITE_MASK;
1083 
1084  //PHY address
1085  temp |= (phyAddr << CSL_MDIO_USER_GROUP_USER_ACCESS_REG_PHYADR_SHIFT) &
1086  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_PHYADR_MASK;
1087 
1088  //Register address
1089  temp |= (regAddr << CSL_MDIO_USER_GROUP_USER_ACCESS_REG_REGADR_SHIFT) &
1090  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_REGADR_MASK;
1091 
1092  //Register value
1093  temp |= data & CSL_MDIO_USER_GROUP_USER_ACCESS_REG_DATA_MASK;
1094 
1095  //Start a write operation
1096  mdioRegs->USER_GROUP[0].USER_ACCESS_REG = temp;
1097 
1098  //Wait for the write to complete
1099  while((mdioRegs->USER_GROUP[0].USER_ACCESS_REG &
1100  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_GO_MASK) != 0)
1101  {
1102  }
1103  }
1104  else
1105  {
1106  //The MAC peripheral only supports standard Clause 22 opcodes
1107  }
1108 }
1109 
1110 
1111 /**
1112  * @brief Read PHY register
1113  * @param[in] opcode Access type (2 bits)
1114  * @param[in] phyAddr PHY address (5 bits)
1115  * @param[in] regAddr Register address (5 bits)
1116  * @return Register value
1117  **/
1118 
1119 uint16_t am64xEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1120  uint8_t regAddr)
1121 {
1122  uint16_t data;
1123  uint32_t temp;
1124  volatile CSL_MdioRegs *mdioRegs;
1125 
1126  //Point to the CPSW0_MDIO registers
1127  mdioRegs = (volatile CSL_MdioRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_MDIO_OFFSET);
1128 
1129  //Valid opcode?
1130  if(opcode == SMI_OPCODE_READ)
1131  {
1132  //Set up a read operation
1133  temp = CSL_MDIO_USER_GROUP_USER_ACCESS_REG_GO_MASK;
1134 
1135  //PHY address
1136  temp |= (phyAddr << CSL_MDIO_USER_GROUP_USER_ACCESS_REG_PHYADR_SHIFT) &
1137  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_PHYADR_MASK;
1138 
1139  //Register address
1140  temp |= (regAddr << CSL_MDIO_USER_GROUP_USER_ACCESS_REG_REGADR_SHIFT) &
1141  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_REGADR_MASK;
1142 
1143  //Start a read operation
1144  mdioRegs->USER_GROUP[0].USER_ACCESS_REG = temp;
1145 
1146  //Wait for the read to complete
1147  while((mdioRegs->USER_GROUP[0].USER_ACCESS_REG &
1148  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_GO_MASK) != 0)
1149  {
1150  }
1151 
1152  //Get register value
1153  data = mdioRegs->USER_GROUP[0].USER_ACCESS_REG &
1154  CSL_MDIO_USER_GROUP_USER_ACCESS_REG_DATA_MASK;
1155  }
1156  else
1157  {
1158  //The MAC peripheral only supports standard Clause 22 opcodes
1159  data = 0;
1160  }
1161 
1162  //Return the value of the PHY register
1163  return data;
1164 }
1165 
1166 
1167 /**
1168  * @brief Write an ALE table entry
1169  * @param[in] index Entry index
1170  * @param[in] entry Pointer to the ALE table entry
1171  **/
1172 
1173 void am64xEthWriteEntry(uint_t index, const Am64xAleEntry *entry)
1174 {
1175  volatile CSL_AleRegs *aleRegs;
1176 
1177  //Point to the CPSW0_ALE registers
1178  aleRegs = (volatile CSL_AleRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_ALE_OFFSET);
1179 
1180  //Copy the content of the entry to be written
1181  aleRegs->ALE_TBLW2 = entry->word2;
1182  aleRegs->ALE_TBLW1 = entry->word1;
1183  aleRegs->ALE_TBLW0 = entry->word0;
1184 
1185  //Write the ALE entry at the specified index
1186  aleRegs->ALE_TBLCTL = CSL_ALE_ALE_TBLCTL_TABLEWR_MASK | index;
1187 }
1188 
1189 
1190 /**
1191  * @brief Read an ALE table entry
1192  * @param[in] index Entry index
1193  * @param[out] entry Pointer to the ALE table entry
1194  **/
1195 
1197 {
1198  volatile CSL_AleRegs *aleRegs;
1199 
1200  //Point to the CPSW0_ALE registers
1201  aleRegs = (volatile CSL_AleRegs *) (CSL_CPSW0_NUSS_BASE + CPSW_ALE_OFFSET);
1202 
1203  //Read the ALE entry at the specified index
1204  aleRegs->ALE_TBLCTL = index;
1205 
1206  //Copy the content of the entry
1207  entry->word2 = aleRegs->ALE_TBLW2;
1208  entry->word1 = aleRegs->ALE_TBLW1;
1209  entry->word0 = aleRegs->ALE_TBLW0;
1210 }
1211 
1212 
1213 /**
1214  * @brief Find a free entry in the ALE table
1215  * @return Index of the first free entry
1216  **/
1217 
1219 {
1220  uint_t index;
1221  uint32_t type;
1222  Am64xAleEntry entry;
1223 
1224  //Loop through the ALE table entries
1225  for(index = 0; index < CPSW_ALE_MAX_ENTRIES; index++)
1226  {
1227  //Read the current entry
1228  am64xEthReadEntry(index, &entry);
1229 
1230  //Retrieve the type of the ALE entry
1232 
1233  //Free entry?
1235  {
1236  //Exit immediately
1237  break;
1238  }
1239  }
1240 
1241  //Return the index of the entry
1242  return index;
1243 }
1244 
1245 
1246 /**
1247  * @brief Search the ALE table for the specified VLAN entry
1248  * @param[in] vlanId VLAN identifier
1249  * @return Index of the matching entry
1250  **/
1251 
1253 {
1254  uint_t index;
1255  uint32_t value;
1256  Am64xAleEntry entry;
1257 
1258  //Loop through the ALE table entries
1259  for(index = 0; index < CPSW_ALE_MAX_ENTRIES; index++)
1260  {
1261  //Read the current entry
1262  am64xEthReadEntry(index, &entry);
1263 
1264  //Retrieve the type of the ALE entry
1266 
1267  //Check the type of the ALE entry
1269  {
1270  //Get the VLAN identifier
1272 
1273  //Compare the VLAN identifier
1274  if(value == CPSW_ALE_WORD1_VLAN_ID(vlanId))
1275  {
1276  //Matching ALE entry found
1277  break;
1278  }
1279  }
1280  }
1281 
1282  //Return the index of the entry
1283  return index;
1284 }
1285 
1286 
1287 /**
1288  * @brief Search the ALE table for the specified VLAN/address entry
1289  * @param[in] vlanId VLAN identifier
1290  * @param[in] macAddr MAC address
1291  * @return Index of the matching entry
1292  **/
1293 
1295 {
1296  uint_t index;
1297  uint32_t value;
1298  Am64xAleEntry entry;
1299 
1300  //Loop through the ALE table entries
1301  for(index = 0; index < CPSW_ALE_MAX_ENTRIES; index++)
1302  {
1303  //Read the current entry
1304  am64xEthReadEntry(index, &entry);
1305 
1306  //Retrieve the type of the ALE entry
1308 
1309  //Check the type of the ALE entry
1311  {
1312  //Get the VLAN identifier
1314 
1315  //Compare the VLAN identifier
1316  if(value == CPSW_ALE_WORD1_VLAN_ID(vlanId))
1317  {
1318  //Compare the MAC address
1319  if(macAddr->b[0] == (uint8_t) (entry.word1 >> 8) &&
1320  macAddr->b[1] == (uint8_t) (entry.word1 >> 0) &&
1321  macAddr->b[2] == (uint8_t) (entry.word0 >> 24) &&
1322  macAddr->b[3] == (uint8_t) (entry.word0 >> 16) &&
1323  macAddr->b[4] == (uint8_t) (entry.word0 >> 8) &&
1324  macAddr->b[5] == (uint8_t) (entry.word0 >> 0))
1325  {
1326  //Matching ALE entry found
1327  break;
1328  }
1329  }
1330  }
1331  }
1332 
1333  //Return the index of the entry
1334  return index;
1335 }
1336 
1337 
1338 /**
1339  * @brief Add a VLAN entry in the ALE table
1340  * @param[in] port Port number
1341  * @param[in] vlanId VLAN identifier
1342  * @return Error code
1343  **/
1344 
1346 {
1347  error_t error;
1348  uint_t index;
1349  Am64xAleEntry entry;
1350 
1351  //Ensure that there are no duplicate address entries in the ALE table
1352  index = am64xEthFindVlanEntry(vlanId);
1353 
1354  //No matching entry found?
1355  if(index >= CPSW_ALE_MAX_ENTRIES)
1356  {
1357  //Find a free entry in the ALE table
1358  index = am64xEthFindFreeEntry();
1359  }
1360 
1361  //Sanity check
1362  if(index < CPSW_ALE_MAX_ENTRIES)
1363  {
1364  //Set up a VLAN table entry
1365  entry.word2 = 0;
1367  entry.word0 = 0;
1368 
1369  //Set VLAN identifier
1370  entry.word1 |= CPSW_ALE_WORD1_VLAN_ID(vlanId);
1371 
1372  //Force the packet VLAN tag to be removed on egress
1375 
1376  //Set VLAN member list
1377  entry.word0 |= CPSW_ALE_WORD0_VLAN_MEMBER_LIST(1 << port) |
1379 
1380  //Add a new entry to the ALE table
1381  am64xEthWriteEntry(index, &entry);
1382 
1383  //Successful processing
1384  error = NO_ERROR;
1385  }
1386  else
1387  {
1388  //The ALE table is full
1389  error = ERROR_FAILURE;
1390  }
1391 
1392  //Return status code
1393  return error;
1394 }
1395 
1396 
1397 /**
1398  * @brief Add a VLAN/address entry in the ALE table
1399  * @param[in] port Port number
1400  * @param[in] vlanId VLAN identifier
1401  * @param[in] macAddr MAC address
1402  * @return Error code
1403  **/
1404 
1406 {
1407  error_t error;
1408  uint_t index;
1409  Am64xAleEntry entry;
1410 
1411  //Ensure that there are no duplicate address entries in the ALE table
1412  index = am64xEthFindVlanAddrEntry(vlanId, macAddr);
1413 
1414  //No matching entry found?
1415  if(index >= CPSW_ALE_MAX_ENTRIES)
1416  {
1417  //Find a free entry in the ALE table
1418  index = am64xEthFindFreeEntry();
1419  }
1420 
1421  //Sanity check
1422  if(index < CPSW_ALE_MAX_ENTRIES)
1423  {
1424  //Set up a VLAN/address table entry
1425  entry.word2 = 0;
1427  entry.word0 = 0;
1428 
1429  //Multicast address?
1430  if(macIsMulticastAddr(macAddr))
1431  {
1432  //Set port mask
1433  entry.word2 |= CPSW_ALE_WORD2_SUPER |
1436 
1437  //Set multicast forward state
1439  }
1440 
1441  //Set VLAN identifier
1442  entry.word1 |= CPSW_ALE_WORD1_VLAN_ID(vlanId);
1443 
1444  //Copy the upper 16 bits of the unicast address
1445  entry.word1 |= (macAddr->b[0] << 8) | macAddr->b[1];
1446 
1447  //Copy the lower 32 bits of the unicast address
1448  entry.word0 |= (macAddr->b[2] << 24) | (macAddr->b[3] << 16) |
1449  (macAddr->b[4] << 8) | macAddr->b[5];
1450 
1451  //Add a new entry to the ALE table
1452  am64xEthWriteEntry(index, &entry);
1453 
1454  //Successful processing
1455  error = NO_ERROR;
1456  }
1457  else
1458  {
1459  //The ALE table is full
1460  error = ERROR_FAILURE;
1461  }
1462 
1463  //Return status code
1464  return error;
1465 }
1466 
1467 
1468 /**
1469  * @brief Remove a VLAN/address entry from the ALE table
1470  * @param[in] port Port number
1471  * @param[in] vlanId VLAN identifier
1472  * @param[in] macAddr MAC address
1473  * @return Error code
1474  **/
1475 
1477 {
1478  error_t error;
1479  uint_t index;
1480  Am64xAleEntry entry;
1481 
1482  //Search the ALE table for the specified VLAN/address entry
1483  index = am64xEthFindVlanAddrEntry(vlanId, macAddr);
1484 
1485  //Matching ALE entry found?
1486  if(index < CPSW_ALE_MAX_ENTRIES)
1487  {
1488  //Clear the contents of the entry
1489  entry.word2 = 0;
1490  entry.word1 = 0;
1491  entry.word0 = 0;
1492 
1493  //Update the ALE table
1494  am64xEthWriteEntry(index, &entry);
1495 
1496  //Successful processing
1497  error = NO_ERROR;
1498  }
1499  else
1500  {
1501  //Entry not found
1502  error = ERROR_NOT_FOUND;
1503  }
1504 
1505  //Return status code
1506  return error;
1507 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
uint8_t opcode
Definition: dns_common.h:188
error_t am64xEthInitPort2(NetInterface *interface)
AM64x Ethernet MAC initialization (port 2)
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
#define netEvent
Definition: net_legacy.h:196
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
error_t am64xEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void macAddrToEui64(const MacAddr *macAddr, Eui64 *interfaceId)
Map a MAC address to the IPv6 modified EUI-64 identifier.
Definition: ethernet.c:946
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
#define CPSW_ALE_MAX_ENTRIES
void am64xEthEnableIrq(NetInterface *interface)
Enable interrupts.
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
#define CPSW_ALE_WORD1_ENTRY_TYPE_VLAN_ADDR
uint8_t data[]
Definition: ethernet.h:222
ALE table entry.
#define ETH_MAX_FRAME_SIZE
Definition: ethernet.h:110
void am64xEthReadEntry(uint_t index, Am64xAleEntry *entry)
Read an ALE table entry.
#define CPSW_ALE_WORD2_PORT_MASK(n)
bool_t addFlag
Definition: ethernet.h:265
void am64xEthWriteEntry(uint_t index, const Am64xAleEntry *entry)
Write an ALE table entry.
#define CPSW_ALE_WORD2_SUPER
#define CPSW_ALE_WORD0_VLAN_MEMBER_LIST(n)
uint8_t type
Definition: coap_common.h:176
uint_t am64xEthFindVlanAddrEntry(uint_t vlanId, MacAddr *macAddr)
Search the ALE table for the specified VLAN/address entry.
error_t am64xEthAddVlanAddrEntry(uint_t port, uint_t vlanId, MacAddr *macAddr)
Add a VLAN/address entry in the ALE table.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define CPSW_ALE_WORD1_ENTRY_TYPE_VLAN
#define osExitIsr(flag)
#define SMI_OPCODE_WRITE
Definition: nic.h:66
void am64xEthTick(NetInterface *interface)
AM64x Ethernet MAC timer handler.
#define TRACE_ERROR(...)
Definition: debug.h:75
#define CPSW_CH0
uint_t am64xEthFindVlanEntry(uint_t vlanId)
Search the ALE table for the specified VLAN entry.
error_t am64xEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
void am64xEthDisableIrq(NetInterface *interface)
Disable interrupts.
#define FALSE
Definition: os_port.h:46
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
void am64xEthInitInstance(NetInterface *interface)
Initialize CPSW instance.
#define CPSW_ALE_WORD1_VLAN_ID_MASK
__weak_func void am64xEthInitGpio(NetInterface *interface)
GPIO configuration.
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:104
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
uint32_t word2
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ ERROR_INVALID_LENGTH
Definition: error.h:111
error_t am64xEthDeleteVlanAddrEntry(uint_t port, uint_t vlanId, MacAddr *macAddr)
Remove a VLAN/address entry from the ALE table.
#define NetTxAncillary
Definition: net_misc.h:36
uint32_t word0
#define SMI_OPCODE_READ
Definition: nic.h:67
uint32_t word1
#define CPSW_ALE_WORD1_MCAST_FWD_STATE(n)
uint_t am64xEthFindFreeEntry(void)
Find a free entry in the ALE table.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
MacAddr
Definition: ethernet.h:195
error_t am64xEthAddVlanEntry(uint_t port, uint_t vlanId)
Add a VLAN entry in the ALE table.
const NicDriver am64xEthPort1Driver
AM64x Ethernet MAC driver (port1)
uint16_t port
Definition: dns_common.h:267
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define CPSW_ALE_WORD0_FORCE_UNTAG_EGRESS(n)
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
#define CPSW_ALE_WORD1_ENTRY_TYPE_MASK
uint8_t n
error_t am64xEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
MAC filter table entry.
Definition: ethernet.h:262
#define osEnterIsr()
void am64xEthEventHandler(NetInterface *interface)
AM64x Ethernet MAC event handler.
uint8_t value[]
Definition: tcp.h:369
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
#define CPSW_PORT2
#define MDIO_OUTPUT_CLK
void am64xEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define CPSW_PORT1
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define CPSW_ALE_WORD1_ENTRY_TYPE_FREE
uint16_t am64xEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define CPSW_ALE_WORD1_VLAN_ID(n)
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
bool_t deleteFlag
Definition: ethernet.h:266
void am64xEthRxIrqHandler(void *arg)
AM64x Ethernet MAC receive interrupt.
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define CPSW_PORT0
NIC driver.
Definition: nic.h:286
AM64x Ethernet MAC driver.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define MDIO_INPUT_CLK
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
error_t am64xEthInitPort1(NetInterface *interface)
AM64x Ethernet MAC initialization (port 1)
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
const NicDriver am64xEthPort2Driver
AM64x Ethernet MAC driver (port2)