PDK API Guide for J7200
Enet Integration Guide

Getting Familiar with Enet LLD APIs


The Enet LLD APIs can be broadly divided into two categories: control and data path. The control APIs can be used to configure all Ethernet hardware submodules like FDB, MAC port, host port, MDIO, statistics, as well as PHY drivers and resource management. The data path APIs are exclusive for the DMA-based data transfers between the TI SoC processing cores and the Ethernet peripheral.

The main APIs of the Enet LLD are the following:

It's worth noting that the control path APIs are mainly IOCTL-based, and the data path APIs are direct functions in order to avoid any additional overhead associated with IOCTL calls as DMA data operations occur highly frequently.

IOCTL Interface


IOCTLs are system calls that take an argument specifying the command code and can take none or additional parameters via Enet_IoctlPrms argument. IOCTL are used by all Enet submodules except for DMA.

The Enet_IoctlPrms parameter structure consists of input and output argument pointers and their corresponding size. The following helper macros are provided to help construct the IOCTL params:

where prms in a pointer to Enet_IoctlPrms variable, in is the pointer to IOCTL input argument and out is the pointer to IOCTL output argument.

It's recommended that the application doesn't set the Enet_IoctlPrms members individually, but only through the helper macros listed above.

Please refer to the individual IOCTL command to find out if it requires input and/or output parameters.

Back To Top

Integrating Enet LLD into User's Application


Developers who wish to add network connectivity to the applications running on TI SoCs, will have to integrate Enet LLD by following the below sequence:

  1. Init Sequence. One-time initialization before using any Enet LLD APIs.
  2. Peripheral Open Sequence. Opens an Ethernet peripheral, it's called for each peripheral that the application intends to use, i.e. ICSSG0 and CPSW.
  3. Port Open Sequence. Opens a MAC port. For peripherals that provide multiple MAC port (i.e. CPSW9G that has 8 MAC ports), this sequence must be followed for each MAC port. This section also covers MAC-PHY and MAC-MAC links.
  4. Packet Send/Receive Sequence. DMA TX and RX channel open sequences as well as functions to use to submit and retrieve queue of packets to/from the driver.
  5. Packet Timestamping Sequence. TX and RX packet timestamping sequence to enable timestamping and retrieval mechanism.
  6. Port Close Sequence. Closes a MAC port. Application has to close all MAC ports which were opened in step 3 when no longer needs those ports.
  7. Peripheral Close Sequence. Closes an Ethernet peripheral when the application no longer needs it. This sequence must be followed for each peripheral that was opened in step 2.
  8. Deinit Sequence. One-time deinitialization once application is done using Enet LLD.

Each of these sequences will be covered in detail in the following sections.

Init Sequence

This is a one-time initialization where the application sets the OSAL and utils functions that Enet LLD will use throughout its lifecycle.

At this stage Enet LLD also initializes its SoC layer which contains data about the Ethernet hardware available in the TI device.

The application should follow the next steps:

  1. (Optional) Enet_initOsalCfg() to initialize the OSAL configuration (see EnetOsal_Cfg) with a default implementation. The default implementation of Enet OSAL interface is based on PDK OSAL layer. Typically, applications can directly use the default Enet OSAL implementation, unless Enet is being used on another OS (i.e. QNX) of if OS is not supported by PDK OSAL layer.
  2. (Optional) Enet_initUtilsCfg() to initialize utils configuration (see EnetUtils_Cfg) with a default implementation. The default implementation of Enet Utils interface is UART-based logging and one-to-one address translations (physical-to-virtual and virtual-to-physical). Applications may want to pass their own utils' print function if UART is not available. Similarly, if a MMU is present and used, applications may need to pass their own address translation functions corresponding to the MMU configuration.
     utilsCfg.print = UART_printf;
     utilsCfg.physToVirt = &myPhysToVirtFxn;
     utilsCfg.virtToPhys = &myVirtToPhysFxn;
    
  3. Enet_init() to pass the OSAL and utils configurations setup in the previous two steps. The application can pass NULL to either the OSAL config or utils config if it intends to use the driver's default implementation.

Peripheral Open Sequence

This is an initialization that needs to be done for each peripheral in the system. The configuration parameters described in this section are peripheral specific.

Application should follow the next steps:

  1. Initialize the peripheral configuration parameters with default values using Enet_initCfg(). Although the application can fill all parameters manually, it's recommended to first get the driver's default values for all parameters and only overwrite the parameters of interest.
    • CPSW peripheral configuration - Cpsw_Cfg structure has the configuration parameters for CPSW Enet Peripheral, such as:
  2. Once done with the configuration of the parameters, the UDMA driver has to be opened. Enet utils library provides a helper function called EnetAppUtils_udmaOpen() to open the UDMA driver, and returns a handle that can be passed to the peripheral configuration parameters, i.e. Cpsw_Cfg::dmaCfg.
  3. Enet_open() to open a peripheral, passing the configuration parameters previously initialized. Enet_open() function takes the following arguments:
    • Peripheral type - This specifies the type or class of the peripheral, i.e. CPSW, ICSSG or other.
    • Instance number - This argument specifies the instance number of the peripheral. Refer to Enet Peripherals section for further information about specific peripheral types and instance numbers.
    • Configuration structure - A pointer to the peripheral-specific configuration structure, i.e. Cpsw_Cfg or Icssg_Cfg.
    • Size of the configuration structure.
  4. If the module is opened successfully, the API will return a valid handle pointer to the Enet driver. It's worth noting that there will be a unique Enet handle (Enet_Handle) for each peripheral opened.
  5. Attach the core with the Resource Manager (RM) using ENET_PER_IOCTL_ATTACH_CORE. IOCTL. To use IOCTLs, the application must have the following:
    • Valid handle to the driver.
    • Core ID, which can be obtained using EnetSoc_getCoreId().
    • Valid IOCTL command.
    • Valid pointer to the IOCTL parameters.
  6. Once the application attaches the core with Resource Manager (RM), the IOCTL call will return core key which has to be used in all further RM-related calls.
  7. A MAC address for the host port is to be obtained using Enet utils helper function EnetAppUtils_allocMac() and the corresponding entry in the ALE table can be added using EnetAppUtils_addHostPortEntry().
  8. Allocate memory for Ring Accelerators, Ethernet packets, etc. Enet LLD examples use EnetAppMemUtils to take care of all memory allocation and freeing operations. The developer can take this as reference or can implement their own memory allocation functions.

Port Open Sequence

The MAC ports can be opened in MAC-to-PHY or MAC-to-MAC mode. In MAC-to-PHY mode, Enet LLD's PHY driver state machine will be used to configure the Ethernet PHY. In MAC-to-MAC mode, the PHY driver will be bypassed entirely.

The link speed and duplexity in MAC-to-PHY can be fixed or auto-negotiated, while in MAC-to-MAC, both link speed and duplexity can be fixed only and must be provided by application.

The steps to open and configure ports in either MAC-to-PHY or MAC-to-MAC modes are shown below.

MAC-PHY link

  1. Set the port number in EnetPer_PortLinkCfg structure.
  2. Set the MAC port interface (RMII, RGMII, SGMII, etc) through the layer, sublayer and variant fields of EnetPer_PortLinkCfg::mii.
  3. The MAC port configuration parameters is peripheral dependent.
    • CPSW MAC Port configuration:
      • Use CpswMacPort_initCfg() to initialize the CPSW MAC port configuration parameters to their default values. Overwrite any parameters as needed.
      • If loopback is to be enabled, set enableLoopback flag in MAC configuration to true. For loopback to be functional the secure flag in host port ALE entry must be set to false. The host port entry update can be done using the CPSW_ALE_IOCTL_ADD_UCAST command.
  4. Set PHY configuration parameters: generic and model specific.
    1. Use EnetPhy_initCfg() to initialize the PHY generic parameters to their default values, such as auto-negotiation capabilities, strap enable/disable, loopback, etc.
    2. Use PHY specific init config functions to initialize model specific parameters. This init config function is provided by the Ethernet PHYs supported in Enet LLD. For example, Dp83867_initCfg() is used to initialize config params for DP83867 PHYs.
    3. Application can also use the Enet helper function EnetBoard_getPhyCfg() to get PHY configuration information for PHYs in TI EVMs.
  5. Set the link speed and duplexity configuration in EnetPer_PortLinkCfg::linkCfg.
  6. Once all the MAC and PHY configurations are done, the ports can be opened by calling the ENET_PER_IOCTL_OPEN_PORT_LINK command.
  7. CPSW Note: To enable RMII on CPSW9G, external 50 MHz RMII clock from PHY is used on SOC RMII_REF_CLOCK pin. On GESI board, this clock is connected as resistor R225 is not populated. To get RMII_50MHZ_CLK, resistor R225 needs to be populated. We need to move R226 to R225 on GESI board to get this clock.
  8. If all the above steps succeeded without any errors, then the Enet driver, the Ethernet peripheral and a MAC port have been opened successfully.
  9. After opening the port, the driver will run its PHY state machine to configure the PHY and eventually get link up status. Application can query the port link using ENET_PER_IOCTL_IS_PORT_LINK_UP.
    • Application can check the PHY alive status (i.e. whether PHY is present on the MDIO bus) using the ENET_MDIO_IOCTL_IS_ALIVE command.
  10. Once link up is detected, application should do the following steps:

The following code snippet shows how a MAC-PHY link is opened (step 1-6 above). CPSW MAC port 1 connected to a DP83867 RGMII PHY has been chosen for this example.

EnetPer_PortLinkCfg portLinkCfg;
EnetMacPort_LinkCfg *linkCfg = &portLinkCfg.linkCfg;
EnetMacPort_Interface *mii = &portLinkCfg.mii;
CpswMacPort_Cfg cpswMacCfg;
EnetPhy_Cfg *phyCfg = &portLinkCfg.phyCfg;
Dp83867_Cfg dp83867Cfg;
/* Step 1 - MAC port 1 */
portLinkCfg->macPort = ENET_MAC_PORT_1;
/* Step 2 - Set port type to RGMII */
/* Step 3 - Initialize MAC port configuration parameters */
CpswMacPort_initCfg(&cpswMacCfg);
portLinkCfg.macCfg = &cpswMacCfg;
/* Step 4a - Set PHY generic configuration parameters */
phyCfg->phyAddr = 0U;
/* Step 4b - DP83867 PHY specific configuration */
Dp83867_initCfg(&dp83867Cfg);
dp83867Cfg.ledMode[2] = DP83867_LED_RXTXACT;
EnetPhy_setExtendedCfg(phyCfg, &dp83867Cfg, sizeof(dp83867Cfg));
/* Step 5 - Set link speed/duplexity to auto-negotiation */
/* Step 6 - Open port link */
ENET_IOCTL_SET_IN_ARGS(&prms, &portLinkCfg);
status = Enet_ioctl(hEnet, coreId, ENET_PER_IOCTL_OPEN_PORT_LINK, &prms);

MAC-to-MAC link

  1. Set the port number in EnetPer_PortLinkCfg::macPort.
  2. Set the MAC port interface (RMII, RGMII, SGMII, etc) through the layer, sublayer and variant fields of EnetPer_PortLinkCfg::mii.
  3. Initialize the MAC configuration parameters using CpswMacPort_initCfg() and manually overwrite any parameters that differ from defaults.
  4. Set PHY address to ENETPHY_INVALID_PHYADDR to indicate that this is a PHY-less connection.
  5. Set the link speed and duplexity configuration in EnetPer_PortLinkCfg::linkCfg to match those of the partner MAC port. The speed and duplexity must be fixed values, they can't be ENET_SPEED_AUTO or ENET_DUPLEX_AUTO as they are used for auto-negotiation which is not relevant in MAC-to-MAC mode.
  6. Once all the MAC and PHY configurations are done, the ports can be opened by calling the ENET_PER_IOCTL_OPEN_PORT_LINK command.
  7. If all the above steps succeeded without any errors, then the Enet driver, the Ethernet peripheral and a MAC port have been opened successfully.
  8. Once link up is detected, application should do the following steps:

The following code snippet shows how a MAC-to-MAC link is opened (steps 1-6 above). CPSW MAC port 1 connected to partner MAC using RGMII interface at 1 Gbps.

EnetPer_PortLinkCfg portLinkCfg;
EnetMacPort_LinkCfg *linkCfg = &portLinkCfg.linkCfg;
EnetMacPort_Interface *mii = &portLinkCfg.mii;
CpswMacPort_Cfg cpswMacCfg;
EnetPhy_Cfg *phyCfg = &portLinkCfg.phyCfg;
/* Step 1 - MAC port 1 */
portLinkCfg->macPort = ENET_MAC_PORT_1;
/* Step 2 - Set port type to RGMII */
/* Step 3 - Initialize MAC port configuration parameters */
CpswMacPort_initCfg(&cpswMacCfg);
portLinkCfg.macCfg = &cpswMacCfg;
/* Step 4 - Indicate that this is a PHY-less MAC-to-MAC connection */
/* Step 5 - Link speed/duplexity must be explicit set, cannot be set to auto */
/* Step 6 - Open port link */
ENET_IOCTL_SET_IN_ARGS(&prms, &portLinkCfg);
status = Enet_ioctl(hEnet, coreId, ENET_PER_IOCTL_OPEN_PORT_LINK, &prms);

Packet Send/Receive Sequence

  1. The DMA channels to enable data transfer are to be opened. It can be done using the below steps:
  2. Now that the Ethernet peripheral (CPSW or ICSSG) and UDMA are configured, the application can start the data transfer.
    • To transmit data from application:
    • To receive packets that are queued up in the CPSW or ICSSG hardware which are ready to be received by the application:

Packet Timestamping Sequence

  1. RX packet timestamping doesn't require any enable sequence. The timestamps in nanoseconds will be returned to the application along with the DMA packet info data, that is, in the EnetUdma_PktTsInfo::rxPktTs field of EnetUdma_PktInfo::tsInfo after retrieving RX packets using EnetDma_retrieveRxPktQ().
  2. Application must register a callback function in advance for TX timestamp event (ENET_EVT_TIMESTAMP_TX) via Enet_registerEventCb() function. The callback registration can be done at any time before enabling TX timestamping.
  3. TX packet timestamping requires to be enabled per packet via DMA packet info EnetUdma_PktInfo::tsInfo structure:
  4. After the packet is submitted for transmission using EnetDma_submitTxPktQ(), the timestamp can be retrieved using Enet_poll() function.
    • Application calls Enet_poll() with event type ENET_EVT_TIMESTAMP_TX periodically until the register callback is called.
    • The MAC port where timestamp is being polled is specified via Enet_poll() arg parameter.
    • The returned timestamp is a value in clock cycles for CPSW peripheral and a value in nanoseconds for ICSSG peripheral.

IOCTL Sequence

  1. Some common IOCTLs have already been mentioned in this document so far. But the application can run any other IOCTL supported by the peripheral. There are two kinds of IOCTLs: synchronous and asynchronous. Asynchronous IOCTLs require an additional completion poll step which is explained in Synchronous and Asynchronous IOCTLs section of the Enet LLD IOCTL interface document.

Port Close Sequence

  1. MAC ports that were opened earlier can be closed using ENET_PER_IOCTL_CLOSE_PORT_LINK IOCTL command. This will close the PHY state machine associated with this MAC port, if the port was not open in MAC-to-MAC mode. Application can choose to reopen the port at any time in the future by following the steps listed in Port Open Sequence section.

Peripheral Close Sequence

  1. Disable the host port using the ENET_HOSTPORT_IOCTL_DISABLE command
  2. Close the opened Tx Channel and Rx flow:
    • Close the Rx flow using EnetAppUtils_closeRxFlow().
    • Close the Tx Channel using EnetAppUtils_closeTxCh().
  3. Detach the core from Resource Manager using the ENET_PER_IOCTL_DETACH_CORE command.
  4. Enet driver can now be closed and de-initialized using Enet_close() and Enet_deinit().

Deinit Sequence

This is one-time deinitialization sequence that must be followed when the application no longer wants to use the Enet LLD.

  1. Enet_deinit() should be called to deinitialize the driver. No further Enet LLD APIs should be called from this point.
  2. Finally, close the UDMA driver using EnetAppUtils_udmaclose()

Back To Top

Peripheral-specific


Back To Top