AM263Px MCU+ SDK: Ethernet PHY Driver User Guide

| AM263Px MCU+ SDK 26.00.00 |

Ethernet PHY Driver User Guide

# Introduction

The Ethernet PHY driver is currently part of the Enet low-level driver (LLD), it's dedicated to Ethernet PHY management. It implements a state machine required to handle the lifecycle of PHYs, from initialization to link establishment.

The PHY submodule interacts with an underlying MDIO hardware through a simple MDIO driver abstraction (see EnetPhy_Mdio) in order to perform operations like detecting alive and/or linked PHYs, and for PHY register accesses. The relationship between PHY, MDIO and Enet LLD integration layer is shown below.

Currently, the PHY driver supports only Clause-22 devices. Clause-45 devices are not supported, but read and write helper functions are provided.

# PHY Driver

The top-layer of PHY driver is located at `source/networking/enet/core/src/phy/enetphy.c`. This layer implements the basic APIs that are needed to communicate the driver, such as `EnetPhy_open()`, `EnetPhy_tick()`, `EnetPhy_close()`, etc.

The Enet LLD is capable of supporting multiple PHYs running simultaneously; each PHY has its own driver instance, its own state machine and hence will follow independent lifecycle from other PHYs.

The lifecycle of the PHYs is handled by the PHY driver via a state machine implementation. This state machine is composed of the following states:

- FINDING: The driver will remain in this state until the PHY is detected as alive and a device-specific PHY driver has been bound to it.
- FOUND: The driver will initiate (soft) reset if requested in PHY configuration.
- RESET_WAIT: The driver will remain in this state while waiting for reset to complete.
- ENABLE: The driver will put the PHY in normal mode, perform PHY device-specific extended configuration and get common capabilities supported by the MAC port and local PHY device. Depending on the requested mode (auto-negotiation or manual), the PHY will either restart auto-negotiation or manually configure speed and duplexity.
- LOOPBACK: Last state if PHY loopback is enabled.
- NWAY_START: The driver will remain in this state while waiting for auto-negotiation to start.
- NWAY_WAIT: The driver will remain in this state while waiting for auto-negotiation to complete.
- LINK_WAIT: The driver will remain in this state while waiting for link up.
- LINKED: The PHY will remain in this state until the link is down, i.e. cable disconnection.

The diagram in the figure below provides a simplified view of the state transitions of the PHY state machine.

Refer to Appendix A for a more detailed view of the PHY state machine.

## Device-Specific Drivers

The PHY driver model has been designed to partition device-specific operations from device-agnostic common operations. The former are implemented by PHY device specific drivers, while the latter can be carried out directly by the main PHY driver.

This model facilitates the addition of new drivers for PHY devices not yet supported in the Enet LLD. The `Phy_DrvObj_t` structure is defined as the interface that device specific drivers must implement. Since this structure is not exposed to the application, its scope is internal to the Enet LLD.

The members of the `Phy_DrvObj_t` structure can be mandatory or optional in nature. Optional members can be set to NULL if the PHY doesn't provide an implementation for them. The list below provides a description of the purpose of each `Phy_DrvObj_t` member.

- name: Driver name.
- bind: The main PHY driver will call this function to bind the driver handle and register access functions to specific PHY device.
- isPhyDevSupported(): Function pointer used by the main PHY driver to check if this device specific driver support a given PHY hardware identified by its version (OUI). This function is used during PHY device to driver binding.
- isMacModeSupported(): The main PHY driver will call this function to check if the device specific driver supports the requested MAC mode (MII, RMII, RGMII, SGMII, etc).
- config(): The main PHY driver will call this function to allow the driver to perform any device-specific extended configuration. This function is optional and will not be called if the driver sets the function pointer to `NULL`.
- reset(): Device specific reset. This function is optional and will not be called if the driver sets the function pointer to `NULL`.
- isResetComplete(): The main PHY driver will call this function to check if the reset operation triggered by `reset()` function has completed. If `reset()` is provided, `isResetComplete()` must be provided as well.
- readExtReg(): The main PHY driver will call this function to read extended registers.
- writeExtReg(): The main PHY driver will call this function to write extended registers.

- printRegs(): The main PHY driver will call this function when EnetPhy_printRegs() is called. This function is optional and will not be called if the driver sets the function pointer to `NULL`.

  The below functions are optional and can only be supported when the PHY has a built-in PTP clock.

- adjPtpFreq(): The main PHY driver will call this function when EnetPhy_adjPtpFreq() is called to adjust PTP clock frequency.
- adjPtpPhase(): The main PHY driver will call this function when EnetPhy_adjPtpPhase() is called to adjust PTP clock phase.
- getPtpTime(): The main PHY driver will call this function when EnetPhy_getPtpTime() is called to get current PHY PTP clock time.
- setPtpTime(): The main PHY driver will call this function when EnetPhy_setPtpTime() is called to set PHY PTP clock time.
- getPtpTxTime(): The main PHY driver will call this function when EnetPhy_getPtpTxTime() is called to get PHY PTP TX packet timestamp.
- getPtpRxTime(): The main PHY driver will call this function when EnetPhy_getPtpRxTime() is called to get PHY PTP RX packet timestamp.
- waitPtpTxTime(): The main PHY driver will call this function when EnetPhy_waitPtpTxTime() is called to add PHY PTP TX packet info to a waiting TX timestamp list.
- procStatusFrame(): The main PHY driver will call this function when EnetPhy_procStatusFrame() is called to process PHY status frame.
- getStatusFrameEthHeader(): The main PHY driver will call this function when EnetPhy_getStatusFrameEthHeader() is called to get the Ethernet header of the PHY status frame.
- enablePtp(): The main PHY driver will call this function when EnetPhy_enablePtp() is called to enable/disable the PHY PTP module.
- tickDriver(): The main PHY driver will call this function when EnetPhy_tickDriver() is called to provide timer tick to the driver.
- enableEventCapture(): The main PHY driver will call this function when EnetPhy_enableEventCapture() is called to enable/disable an event capture on a PHY GPIO pin. This function can only be supported when the built-in PTP clock supports event capture.
- enableTriggerOutput(): The main PHY driver will call this function when EnetPhy_enableTriggerOutput() is called to enable/disable trigger output on a GPIO pin. This function can only be supported when the built-in PTP clock supports trigger output.
- getEventTs(): The main PHY driver will call this function when () is called when EnetPhy_getEventTs() is called to get event timestamp.

The current version of Enet LLD includes the following PHY drivers:

- Generic PHY driver.
- TI DP83867 RGMII PHY driver.
- TI DP83869 RGMII PHY driver.
- TI DP83822 RMII PHY driver.
- TI DP83826 RMII PHY driver.
- TI DP83TG720 Automotive PHY driver.
- TI DP83TC812 Automotive PHY driver.

The generic PHY driver is a generic case with limited support for IEEE-Standard MII registers. Reuse of PHY generic function by other device-specific drivers is possible when their `Phy_DrvObj_t` implementation doesn't deviate from standard. The diagram in figure below shows the reuse of extended register read/write functions by the DP83867 driver.

Device specific drivers can be found at `source/board/ethphy/enet/rtos_drivers/src/*`.

# Custom Board Support

The MCU+SDK enet driver supports a set of boards for each SoC out of the box

- Refer MCU+SDK release notes for platforms/board supported for each SoC

The board specific portion of the enet code is auto generated in the file ti_board_config.c for supported boards

For porting enet based applications to custom board the following need to be done: Enable "Custom Board" syscfg option

- Enabling “Custom Board” will prevent auto generation of board specific code.
- A C file will have to be then written that is specific to the board.

### Board config C file

The board specific file should contain the following

- const EnetPhy_DrvInfoTbl gEnetPhyDrvTbl: This is a table of ENET PHY drivers supported on the board. Refer Enet custom PHY integration guide for details on how to populate this table Ethernet PHY Driver User Guide
- EnetBoard_setupPorts(): This function should setup any board level muxes and configure any SoC level RGMII internal delay/ RMII configuration for the specific port.
  - Refer API documentation for mcu_plus_sdk/source/networking/enet/utils/include/enet_board.h for details of function and arguments
- EnetBoard_getPhyCfg(): This function should return the ETHPHY specific configuration for a given port including any extended phy configuration
  - Refer API documentation for mcu_plus_sdk/source/networking/enet/utils/include/enet_board.h for details of function and arguments
- EnetBoard_getMacAddrList(): This function should populate any board specific MAC addresses that are available on board eeprom. If the board does not have any board specific macAddresses this function should set argument `*pAvailMacEntries = 0`
- EnetBoard_getId(): This function should return the board id. This is not used anywhere outside this file so the board id returned will depend on the implementation of EnetBoard_setupPorts()/EnetBoard_getPhyCfg() for the custom board if it refers the boardId to determine PHY config/setup ports.
- Refer mcu_plus_sdk/examples/networking/enet_layer2_multi_channel
  - enet_custom_board_config.c for example illustrating custom board integration

## PHY to Driver Binding

The PHY-to-driver binding is the process of selecting the best driver for a PHY device based on the device's unique identifier. This process is done by the main PHY driver upon alive detection of a PHY device and takes place in the FINDING state.

The device unique identifier is read from PHYIDR1 and PHYIDR2 registers and populated into a structure of type EnetPhy_Version.

The main PHY driver has a `gEnetPhyDrvs` array which contains all device specific drivers that are registered and that will participate in the search for the best driver for the PHY that had been recently discovered.

static const EthPhyDrv_If gEnetPhyDrvs[] =
{
&gEnetPhyDrvDp83822, /* DP83822 */
&gEnetPhyDrvDp83867, /* DP83867 */
&gEnetPhyDrvDp83869, /* DP83869 */
&gEnetPhyDrvGeneric, /* Generic PHY - must be last */
};

In the search process, the main PHY driver will call the `isPhyDevSupported()` function of each registered driver. The drivers will use the EnetPhy_Version which is passed as an argument in order to determine whether the device is supported or not. If it is, `isPhyDevSupported()` must return `true` and the search process ends. If not, the search continues with the next registered device.

The generic PHY (which must be the last one in the `gEnetPhyDrvs` array) will be bound to the device if no other driver can support a given PHY, but the PHY full functionality can't be guaranteed.

# Implementing a New PHY Driver

You can find the guide for implementing a new PHY Driver here.

# MAC2MAC feature (NO-PHY mode)

You can find the guide to enable MAC2MAC support here.

# Appendix

## Appendix A

Detailed view of the PHY state machine.

Phy_DrvObj_t
Definition: phy_common.h:305