/**
******************************************************************************
* @file sdk/include/lib/ethernet_phy/eth_phy.h
* @author HUGE-IC Application Team
* @version V1.0.0
* @date 10-10-2018
* @brief Framework and drivers for configuring and reading different PHYs
******************************************************************************
* @attention
*
*
© COPYRIGHT 2018 HUGE-IC
*
*
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ETH_PHY_H__
#define __ETH_PHY_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "ethtool.h"
#include "mii.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @weakgroup NETWORK_PHY
* @{
*/
/** @defgroup NETWORK_PHY_Exported_Constants Exported Constants
* @{
*/
#define PHY_ADAPTIVE_ADDR -1
#define PHY_INIT_TIMEOUT 100000
#define PHY_STATE_TIME 1
#define PHY_FORCE_TIMEOUT 10
#define PHY_AN_TIMEOUT 10
#define PHY_MAX_ADDR 32
#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | \
SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg | \
SUPPORTED_TP | \
SUPPORTED_MII)
#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
SUPPORTED_1000baseT_Half | \
SUPPORTED_1000baseT_Full)
/**
* @}
*/
/** @defgroup NETWORK_PHY_Exported_Typedefs Exported Typedefs
* @{
*/
struct netdev;
struct ethernet_phy_device;
/* PHY state machine states:
*
* DOWN: PHY device and driver are not ready for anything. probe
* should be called if and only if the PHY is in this state,
* given that the PHY device exists.
* - PHY driver probe function will, depending on the PHY, set
* the state to STARTING or READY
*
* STARTING: PHY device is coming up, and the ethernet driver is
* not ready. PHY drivers may set this in the probe function.
* If they do, they are responsible for making sure the state is
* eventually set to indicate whether the PHY is UP or READY,
* depending on the state when the PHY is done starting up.
* - PHY driver will set the state to READY
* - start will set the state to PENDING
*
* READY: PHY is ready to send and receive packets, but the
* controller is not. By default, PHYs which do not implement
* probe will be set to this state by phy_probe(). If the PHY
* driver knows the PHY is ready, and the PHY state is STARTING,
* then it sets this STATE.
* - start will set the state to UP
*
* PENDING: PHY device is coming up, but the ethernet driver is
* ready. phy_start will set this state if the PHY state is
* STARTING.
* - PHY driver will set the state to UP when the PHY is ready
*
* UP: The PHY and attached device are ready to do work.
* Interrupts should be started here.
* - timer moves to AN
*
* AN: The PHY is currently negotiating the link state. Link is
* therefore down for now. phy_timer will set this state when it
* detects the state is UP. config_aneg will set this state
* whenever called with phydev->autoneg set to AUTONEG_ENABLE.
* - If autonegotiation finishes, but there's no link, it sets
* the state to NOLINK.
* - If aneg finishes with link, it sets the state to RUNNING,
* and calls adjust_link
* - If autonegotiation did not finish after an arbitrary amount
* of time, autonegotiation should be tried again if the PHY
* supports "magic" autonegotiation (back to AN)
* - If it didn't finish, and no magic_aneg, move to FORCING.
*
* NOLINK: PHY is up, but not currently plugged in.
* - If the timer notes that the link comes back, we move to RUNNING
* - config_aneg moves to AN
* - phy_stop moves to HALTED
*
* FORCING: PHY is being configured with forced settings
* - if link is up, move to RUNNING
* - If link is down, we drop to the next highest setting, and
* retry (FORCING) after a timeout
* - phy_stop moves to HALTED
*
* RUNNING: PHY is currently up, running, and possibly sending
* and/or receiving packets
* - timer will set CHANGELINK if we're polling (this ensures the
* link state is polled every other cycle of this state machine,
* which makes it every other second)
* - irq will set CHANGELINK
* - config_aneg will set AN
* - phy_stop moves to HALTED
*
* CHANGELINK: PHY experienced a change in link state
* - timer moves to RUNNING if link
* - timer moves to NOLINK if the link is down
* - phy_stop moves to HALTED
*
* HALTED: PHY is up, but no polling or interrupts are done. Or
* PHY is in an error state.
*
* - phy_start moves to RESUMING
*
* RESUMING: PHY was halted, but now wants to run again.
* - If we are forcing, or aneg is done, timer moves to RUNNING
* - If aneg is not done, timer moves to AN
* - phy_stop moves to HALTED
*/
enum ethernet_phy_state {
ETH_PHY_DOWN = 0,
ETH_PHY_STARTING,
ETH_PHY_READY,
ETH_PHY_PENDING,
ETH_PHY_UP,
ETH_PHY_AN,
ETH_PHY_RUNNING,
ETH_PHY_NOLINK,
ETH_PHY_FORCING,
ETH_PHY_CHANGELINK,
ETH_PHY_HALTED,
ETH_PHY_RESUMING
};
/* struct phy_driver: Driver structure for a particular PHY type
*
* phy_id: The result of reading the UID registers of this PHY
* type, and ANDing them with the phy_id_mask. This driver
* only works for PHYs with IDs which match this field
* name: The friendly name of this PHY type
* phy_id_mask: Defines the important bits of the phy_id
* features: A list of features (speed, duplex, etc) supported
* by this PHY
* flags: A bitfield defining certain other features this PHY
* supports (like interrupts)
*
* The drivers must implement config_aneg and read_status. All
* other functions are optional. Note that none of these
* functions should be called from interrupt time. The goal is
* for the bus read/write functions to be able to block when the
* bus transaction is happening, and be freed up by an interrupt
* (The MPC85xx has this ability, though it is not currently
* supported in the driver).
*/
struct ethernet_phy_driver {
uint32 features;
/*
* Called to initialize the PHY,
* including after a reset
*/
int (*config_init)(struct ethernet_phy_device *phydev);
/*
* Called during discovery. Used to set
* up device-specific structures, if any
*/
// int (*probe)(struct ethernet_phy_device *phydev);
/* PHY Power Management */
// int (*suspend)(struct ethernet_phy_device *phydev);
// int (*resume)(struct ethernet_phy_device *phydev);
/*
* Configures the advertisement and resets
* autonegotiation if phydev->autoneg is on,
* forces the speed to the current settings in phydev
* if phydev->autoneg is off
*/
int (*config_aneg)(struct ethernet_phy_device *phydev);
/* Determines the negotiated speed and duplex */
int (*read_status)(struct ethernet_phy_device *phydev);
/* Clears any pending interrupts */
// int (*ack_interrupt)(struct ethernet_phy_device *phydev);
/* Enables or disables interrupts */
// int (*config_intr)(struct ethernet_phy_device *phydev);
/*
* Checks if the PHY generated an interrupt.
* For multi-PHY devices with shared PHY interrupt pin
*/
// int (*did_interrupt)(struct ethernet_phy_device *phydev);
/* Clears up any memory if needed */
// void (*remove)(struct ethernet_phy_device *phydev);
/* Returns true if this is a suitable driver for the given
* phydev. If NULL, matching is based on phy_id and
* phy_id_mask.
*/
// int (*match_phy_device)(struct ethernet_phy_device *phydev);
/* Handles ethtool queries for hardware time stamping. */
// int (*ts_info)(struct ethernet_phy_device *phydev, struct ethtool_ts_info *ti);
/* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */
// int (*hwtstamp)(struct ethernet_phy_device *phydev, struct ifreq *ifr);
/*
* Requests a Rx timestamp for 'skb'. If the skb is accepted,
* the phy driver promises to deliver it using netif_rx() as
* soon as a timestamp becomes available. One of the
* PTP_CLASS_ values is passed in 'type'. The function must
* return true if the skb is accepted for delivery.
*/
// bool (*rxtstamp)(struct ethernet_phy_device *dev, struct sk_buff *skb, int type);
/*
* Requests a Tx timestamp for 'skb'. The phy driver promises
* to deliver it using skb_complete_tx_timestamp() as soon as a
* timestamp becomes available. One of the PTP_CLASS_ values
* is passed in 'type'.
*/
// void (*txtstamp)(struct ethernet_phy_device *dev, struct sk_buff *skb, int type);
/* Some devices (e.g. qnap TS-119P II) require PHY register changes to
* enable Wake on LAN, so set_wol is provided to be called in the
* ethernet driver's set_wol function. */
// int (*set_wol)(struct ethernet_phy_device *dev, struct ethtool_wolinfo *wol);
/* See set_wol, but for checking whether Wake on LAN is enabled. */
// void (*get_wol)(struct ethernet_phy_device *dev, struct ethtool_wolinfo *wol);
};
/* phy_device: An instance of a PHY
*
* p_emac_dev: Pointer to the bus this PHY is on
* phy_id: UID for this device found during discovery
* state: state of the PHY for management purposes
* addr: Bus address of PHY
* link_timeout: The number of timer firings to wait before the
* giving up on the current attempt at acquiring a link
* adjust_link: Callback for the enet controller to respond to
* changes in the link state.
* adjust_state: Callback for the enet driver to respond to
* changes in the state machine.
*
* speed, duplex, pause, supported, advertising, and
* autoneg are used like in mii_if_info
*
* interrupts currently only supports enabled or disabled,
* but could be changed in the future to support enabling
* and disabling specific interrupts
*
* Contains some infrastructure for polling and interrupt
* handling, as well as handling shifts in PHY hardware state
*/
struct ethernet_phy_device {
struct dev_obj dev;
/* Bus address of the PHY (0-31) */
int16 addr;
/* phy driver pointer */
struct ethernet_phy_driver *drv;
struct ethernet_mdio_bus *bus;
struct netdev *ndev;
uint32 phy_id;
enum ethernet_phy_state state;
/*
* forced speed & duplex (no autoneg)
* partner speed & duplex & pause (autoneg)
*/
int16 speed;
int16 duplex;
int16 pause;
int16 asym_pause;
/* The most recently read link state */
int16 link;
/* Union of PHY and Attached devices' supported modes */
/* See mii.h for more info */
uint32 supported;
uint32 advertising;
uint32 autoneg;
uint32 link_timeout;
/* last state */
int16 last_speed;
int16 last_duplex;
int16 last_link;
//os_task_t task;
};
/**
* @}
*/
/** @defgroup NETWORK_PHY_Exported_Functions Exported Functions
* @{
*/
extern struct ethernet_phy_driver genphy_driver;
uint16 phy_read(struct ethernet_phy_device *phydev, uint16 reg);
void phy_write(struct ethernet_phy_device *phydev, uint16 reg, uint16 val);
void eth_phy_device_create(struct ethernet_phy_device *dev);
uint8 eth_get_phy_device(struct ethernet_phy_device *dev);
int32 eth_phy_connect_direct(struct ethernet_phy_device *phydev);
uint8 eth_phy_start_aneg(struct ethernet_phy_device *phydev);
int genphy_config_init(struct ethernet_phy_device *phydev);
int genphy_restart_aneg(struct ethernet_phy_device *phydev);
int genphy_config_aneg(struct ethernet_phy_device *phydev);
int genphy_update_link(struct ethernet_phy_device *phydev);
int genphy_read_status(struct ethernet_phy_device *phydev);
void eth_phy_state_machine(struct ethernet_phy_device *phydev);
void eth_phy_start_machine(struct ethernet_phy_device *phydev);
int32 eth_phy_open(struct ethernet_phy_device *phydev, struct ethernet_mdio_bus *mdio_bus, struct netdev *ndev);
void eth_phy_close(struct ethernet_phy_device *phydev);
void eth_phy_attach(uint32 dev_id, struct ethernet_phy_device *phydev);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif //__ETH_PHY_H__
/*************************** (C) COPYRIGHT 2018 HUGE-IC ***** END OF FILE *****/