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.
The top-layer of PHY driver is located at <ENET_LLD>/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:
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.
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 EnetPhy_Drv
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 EnetPhy_Drv
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 EnetPhy_Drv
member.
NULL
.NULL
.reset()
function has completed. If reset()
is provided, isResetComplete()
must be provided as well.NULL
.The current version of Enet LLD includes the following PHY drivers:
The generic PHY driver is a special case because its implementation is limited to IEEE-Standard MII registers. Reuse of PHY generic function by other device-specific drivers is possible when their EnetPhy_Drv
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 <ENET_LLD>/src/phy/*
.
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.
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.
The following list of steps is provided as guideline when adding a new PHY driver for a device which is not supported by Enet LLD.
<ENET_LLD>/include/phy
.<ENET_LLD>/src/phy
. EnetPhy_Drv
, but don't make it static. This variable will be later accessed as an extern symbol by the Ethernet PHY driver.EnetPhy_Drv
structure with the function pointers of the device specific implementation.EnetPhy_Drv
as extern in main PHY driver located at <ENET_LLD>/src/phy/enetphy.c
. Also, add it to the gEnetPhyDrvs
array.SRCS_COMMON
in the Ethernet PHY driver makefile locate at <ENET_LLD>/src/phy/makefile
.SRCDIR
, so just the source name needs to be added.Detailed view of the PHY state machine.