Chapter 171. Ethernet PHY Device Support
Table of Contents
171.1. Ethernet PHY Device API
Modern ethernet subsystems are often separated into two pieces, the media access controller (sometimes known as a MAC) and the physical device or line interface (often referred to as a PHY). In this case, the MAC handles generating and parsing physical frames and the PHY handles how this data is actually moved to/from the wire. The MAC and PHY communicate via a special protocol, known as MII. This MII protocol can handle control over the PHY which allows for selection of such transmission criteria as line speed, duplex mode, etc.
In most cases, ethernet drivers only need to bother with the PHY during system initialization. Since the details of the PHY are separate from the MAC, there are different drivers for each. The drivers for the PHY are described by a set of exported functions which are commonly used by the MAC. The primary use of these functions currently is to initialize the PHY and determine the status of the line connection.
The connection between the MAC and the PHY differs from MAC to MAC, so the actual routines to manipulate this data channel are a property of the MAC instance. Furthermore, there are many PHY devices each with their own internal operations. A complete MAC/PHY driver setup will be comprised of the MAC MII access functions and the PHY internal driver.
A driver instance is contained within a eth_phy_access_t:
#define PHY_BIT_LEVEL_ACCESS_TYPE 0 #define PHY_REG_LEVEL_ACCESS_TYPE 1 typedef struct { int ops_type; // 0 => bit level, 1 => register level bool init_done; void (*init)(void); void (*reset)(void); union { struct { void (*set_data)(int); int (*get_data)(void); void (*set_clock)(int); void (*set_dir)(int); } bit_level_ops; struct { void (*put_reg)(int reg, int unit, unsigned short data); bool (*get_reg)(int reg, int unit, unsigned short *data); } reg_level_ops; } ops; int phy_addr; struct _eth_phy_dev_entry *dev; // Chip access functions } eth_phy_access_t; struct _eth_phy_dev_entry { char *name; cyg_uint32 id; bool (*stat)(eth_phy_access_t *f, int *stat); unsigned int (*event)(eth_phy_access_t *f, unsigned int bitmask); // Configuration option cyg_uint32 idmask; // Masked with id to determine if there's a match };
The dev
element points to the PHY specific support
functions.
Currently, the only function which must be defined is stat()
.
The MAC-MII-PHY interface is a narrow connection, with commands and status
moving between the MAC and PHY using a bit-serial protocol.
Some MAC devices contain the intelligence to run this protocol, exposing
a mechanism to access PHY registers one at a time. Other MAC devices may only
provide access to the MII data lines (or even still, this may be considered
completely separate from the MAC). In these cases, the PHY support layer
must handle the serial protocol.
The choice between the access methods is in the
ops_type
field.
If it has the value
PHY_BIT_LEVEL_ACCESS_TYPE
, then the PHY device layer will
run the protocol, using the access functions
set_data()
,
get_data()
,
set_clock()
,
set_dir()
are used to control the MII signals and run
the protocol.
If ops_type
has the value
PHY_REG_LEVEL_ACCESS_TYPE
,
then the routines
put_reg()
, and
get_reg()
are used to access the PHY registers.
Two additional functions may be defined.
These are
init()
, and
reset()
.
The purpose of these functions is for gross-level management of the
MII interface.
The
init()
function will be called once, at system initialization time.
It should do whatever operations are necessary to prepare the
MII channel.
In the case of
PHY_BIT_LEVEL_ACCESS_TYPE
devices,
init()
should prepare the signals for use, i.e. set up the appropriate
parallel port registers, etc.
The
reset()
function may be called by a driver to cause the PHY device to
be reset to a known state.
Not all drivers will require this and this function may not even
be possible, so it's use and behavior is somewhat target specific.
Currently, the only function required of device specific drivers is
stat()
.
This routine should query appropriate registers in the PHY and return
a status bitmap indicating the state of the physical connection.
In the case where the PHY can auto-negotiate a line speed and condition,
this information may be useful to the MAC to indicate what speed it should
provide data, etc.
The status bitmask contains these bits:
#define ETH_PHY_STAT_LINK 0x0001 // Link up/down #define ETH_PHY_STAT_100MB 0x0002 // Connection is 100Mb/10Mb #define ETH_PHY_STAT_FDX 0x0004 // Connection is full/half duplex
Note: the usage here is that if the bit is set, then the condition
exists. For example, if the
ETH_PHY_STAT_LINK
is set, then a physical link has been established.
For platforms capable of supporting asynchronous PHY event
notification the event()
function can be
implemented. The CDL for the specific PHY and Ethernet driver
combination defines whether
the CYGINT_DEVS_ETH_PHY_PLF_IF_EVENTS
controlled feature
is actually included. The event()
function, for
simplicity, provides both the event control and status support
depending on the bitmask
setting passed to the
function. This function provides the following functionality:
- configure the PHY for the events we are interested in receiving asynchronous notification for
- ascertain which events have occurred when an event is triggered
- clear any pending event (interrupt) status on the PHY
- ascertain the current status of the PHY
All of the above functionality is rolled into the single function to
avoid the need for a separate stat()
call to be
made to the PHY when processing a PHY interrupt at the Ethernet driver
layer. Also the event()
function should never
block, unlike the stat()
implementation which may
block depending on the PHY driver requirements.
In addition to the status bitmask bits defined
for stat()
(as listed above) extra status and
control bits are defined. The status bit:
#define ETH_PHY_STAT_ANC 0x0008 // Auto-Negotiation Completed
is used to reflect whether Auto-Negotiation has completed. When requesting enable/disable control, or detecting a change in state indicated in the function result, the extra bits:
#define ETH_PHY_EVENT_LINK (1 << 16) // Link up/down change #define ETH_PHY_EVENT_SPEED (1 << 17) // Speed (e.g. 10-/100-Mb/s) change #define ETH_PHY_EVENT_DUPLEX (1 << 18) // Duplex (half/full) change #define ETH_PHY_EVENT_AUTONEG (1 << 19) // Auto-Negotiation completed
are available. When passing the bitmask
to the
function the bit:
#define ETH_PHY_EVENT_UPDATE (1 << 31) // Update enabled events
is used to control both the enabling and disabling of specific PHY
events. If ETH_PHY_EVENT_UPDATE
if set then
the ETH_PHY_EVENT_
bit setting is used to control
the enable (bit is set) or disable (bit is clear) state of the
corresponding PHY event. If
this ETH_PHY_EVENT_UPDATE
bit is not set then the
PHY event configuration is not changed, allowing the function call to
be used purely for the clearing of pending events and ascertaing the
event status and current PHY state. The returned result bitmask will
have the bit:
#define ETH_PHY_EVENT_STATUS (1 << 30) // Valid EVENT status flags
set if the event status information returned is valid. This is used to distinguish from the error value 0, used when the underlying PHY operations are either not available (PHY event support not actually included) or an error has occurred.
Note | |
---|---|
The default starting state for PHY drivers is that all PHY events should be disabled. The Ethernet driver then requires an explicit call to enable PHY event support. For example to enable the LINK up/down event, and check that the PHY actually supports the functionality, a driver could make the call: if (_eth_phy_event(eth->phy, (ETH_PHY_EVENT_LINK | ETH_PHY_EVENT_UPDATE)) & ETH_PHY_EVENT_STATUS) { // create, attach and enable platform specific PHY interrupt handler } |
2024-03-18 | Open Publication License |