Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
#include "typesdef.h"
#include "list.h"
#include "errno.h"
#include "dev.h"
#include "osal/string.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "osal/task.h"
#include "hal/netdev.h"
#include "lib/net/ethphy/eth_phy.h"
#include "lib/net/ethphy/eth_mdio_bus.h"
__init int32 eth_mdio_bus_attach(uint32 dev_id, struct ethernet_mdio_bus *p_mdio_bus)
{
dev_register(dev_id, (struct dev_obj *)p_mdio_bus);
return RET_OK;
}
int32 eth_mdio_bus_open(struct ethernet_mdio_bus *p_mdio_bus, struct netdev *p_netdev)
{
struct netdev_hal_ops *ndev_ops = (struct netdev_hal_ops *)p_netdev->dev.ops;
if(!(p_netdev && ndev_ops->mdio_read && ndev_ops->mdio_write && p_mdio_bus)) {
return RET_ERR;
}
p_mdio_bus->priv = p_netdev;
p_mdio_bus->read = (int (*)(void *, uint16, uint16))ndev_ops->mdio_read;
p_mdio_bus->write = (int (*)(void *, uint16, uint16, uint16))ndev_ops->mdio_write;
return RET_OK;
}
int32 eth_mdio_bus_close(struct ethernet_mdio_bus *p_mdio_bus)
{
return RET_OK;
}
int32 eth_mdio_bus_write(struct ethernet_mdio_bus *p_mdio_bus, uint16 phy_addr, uint16 reg_addr, uint16 data)
{
if(p_mdio_bus && p_mdio_bus->write) {
return p_mdio_bus->write(p_mdio_bus->priv, phy_addr, reg_addr, data);
}
return 0;
}
int32 eth_mdio_bus_read(struct ethernet_mdio_bus *p_mdio_bus, uint16 phy_addr, uint16 reg_addr)
{
if(p_mdio_bus && p_mdio_bus->read) {
return p_mdio_bus->read(p_mdio_bus->priv, phy_addr, reg_addr);
}
return 0;
}

View File

@@ -0,0 +1,443 @@
/**
******************************************************************************
* @file sdk/lib/ethernet_phy/eth_phy.c
* @author HUGE-IC Application Team
* @version V1.0.0
* @date 10-10-2018
* @brief Framework for configuring and reading PHY devices
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2018 HUGE-IC</center></h2>
*
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "typesdef.h"
#include "errno.h"
#include "list.h"
#include "dev.h"
#include "osal/task.h"
#include "osal/work.h"
#include "osal/sleep.h"
#include "osal/timer.h"
#include "hal/netdev.h"
#include "lib/common/sysevt.h"
#include "lib/net/ethphy/eth_phy.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
/* Private variables ---------------------------------------------------------*/
/**
* @brief A structure for mapping a particular speed and duplex combination
* to a particular SUPPORTED and ADVERTISED value
*/
struct __phy_setting {
int16 speed;
int16 duplex;
uint32 setting;
};
/**
* @brief A mapping of all SUPPORTED settings to speed/duplex
*/
static const struct __phy_setting settings[] = {
{
.speed = SPEED_1000,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_1000baseT_Full,
},
{
.speed = SPEED_1000,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_1000baseT_Half,
},
{
.speed = SPEED_100,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_100baseT_Full,
},
{
.speed = SPEED_100,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_100baseT_Half,
},
{
.speed = SPEED_10,
.duplex = DUPLEX_FULL,
.setting = SUPPORTED_10baseT_Full,
},
{
.speed = SPEED_10,
.duplex = DUPLEX_HALF,
.setting = SUPPORTED_10baseT_Half,
},
};
struct _eth_phy_wkq {
struct os_work os_work_phy;
struct ethernet_phy_device *eth_phy_dev;
};
static struct _eth_phy_wkq eth_phy_wkq;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup NETWORK
* @{
*/
static void eth_phy_event(struct ethernet_phy_device *phydev, uint32 event, uint32 param1, uint32 param2)
{
const struct netdev_hal_ops *ops = (const struct netdev_hal_ops *)phydev->ndev->dev.ops;
if (ops->phy_event) {
ops->phy_event(phydev, event, param1, param2);
}
}
/** @defgroup NETWORK_PHY PHY Framework
* @brief Framework for finding and configuring PHYs.
* Also contains generic PHY driver
* @{
*/
/**
* @brief return auto-negotiation status
* @param phydev : target phy_device struct
* @retval auto-negotiation status
* @note Reads the status register and returns 0 either if
* auto-negotiation is incomplete, or if there was an error.
* Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
*/
static inline int eth_phy_aneg_done(struct ethernet_phy_device *phydev)
{
int retval;
retval = phy_read(phydev, MII_BMSR);
return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
}
/**
* @brief find a PHY settings array entry that matches speed & duplex
* @param advertising :
* @retval the index of that setting
* @note Searches the settings array for the setting which matches the
* desired speed and duplex, and returns the index of that setting.
* Returns the index of the last setting if none of the others
* match.
*/
static inline int eth_phy_find_setting(uint32 advertising)
{
int idx = 0;
while (idx < ARRAY_SIZE(settings) && (!(advertising & settings[idx].setting))) {
idx++;
}
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
/**
* @brief find a PHY setting that matches the requested features mask
* @param idx : The first index in settings[] to search
* @retval the index of the first valid setting
* @note Returns the index of the first valid setting less than or equal
* to the one pointed to by idx, as determined by the mask in
* features. Returns the index of the last setting if nothing else
* matches.
*/
static inline int eth_phy_find_valid(int idx, uint32 features)
{
while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) {
idx++;
}
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
/**
* @brief make sure the PHY is set to supported speed and duplex
* @param phydev : the target phy_device struct
* @retval None
* @note Make sure the PHY is set to supported speeds and duplexes. Drop
* down by one in this order:
* 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
*/
static void eth_phy_sanitize_settings(struct ethernet_phy_device *phydev)
{
uint32 features = phydev->supported;
int idx;
/* Sanitize settings based on PHY capabilities */
if ((features & SUPPORTED_Autoneg) == 0) {
phydev->autoneg = AUTONEG_DISABLE;
}
idx = eth_phy_find_valid(eth_phy_find_setting(phydev->advertising), features);
phydev->speed = settings[idx].speed;
phydev->duplex = settings[idx].duplex;
}
/**
* @brief start auto-negotiation for this PHY device
* @param phydev : the phy_device struct
* @retval Returning 0 means that the PHY does not support
* auto-negotiation.
* @note Sanitizes the settings (if we're not autonegotiating them), and
* then calls the driver's config_aneg function. If the PHYCONTROL
* Layer is operating, we change the state to reflect the beginning
* of Auto-negotiation or forcing.
*/
uint8 eth_phy_start_aneg(struct ethernet_phy_device *phydev)
{
int err;
if (AUTONEG_DISABLE == phydev->autoneg) {
eth_phy_sanitize_settings(phydev);
}
err = phydev->drv->config_aneg(phydev);
if (err < 0) {
return 0;
}
if (phydev->state != ETH_PHY_HALTED) {
if (AUTONEG_ENABLE == phydev->autoneg) {
phydev->state = ETH_PHY_AN;
} else {
phydev->state = ETH_PHY_FORCING;
}
}
return 1;
}
/**
* @brief start PHY state machine tracking
* @param phydev : the phy_device struct
* @param handler : callback function for state change notifications
* @retval None
* @note The PHY infrastructure can run a state machine which tracks
* whether the PHY is starting up, negotiating, etc. This function
* starts the timer which tracks the state of the PHY. If you want
* to be notified when the state changes, pass in the callback
* @handler, otherwise, pass NULL. If you want to maintain your own
* state machine, do not call this function.
*/
void eth_phy_start_machine(struct ethernet_phy_device *phydev)
{
//phydev->adjust_state = handler;
}
/**
* @brief Handle the state machine
* @param phydev : target phy_device struct
* @retval None
*/
void eth_phy_state_machine(struct ethernet_phy_device *phydev)
{
int needs_aneg = 0;
int err = 0;
int16 link = phydev->link;
int16 speed = phydev->speed;
int16 duplex = phydev->duplex;
//if(phydev->adjust_state) {
// phydev->adjust_state(phydev);
//}
switch (phydev->state) {
case ETH_PHY_DOWN:
case ETH_PHY_STARTING:
case ETH_PHY_READY:
case ETH_PHY_PENDING:
break;
case ETH_PHY_UP:
needs_aneg = 1;
break;
case ETH_PHY_AN:
err = phydev->drv->read_status(phydev);
if (err < 0) {
break;
}
/* If the link is down, give up on
* negotiation for now */
if (!phydev->link) {
phydev->state = ETH_PHY_NOLINK;
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
break;
}
/* Check if negotiation is done. Break
* if there's an error */
err = eth_phy_aneg_done(phydev);
if (err < 0) {
break;
}
/* If AN is done, we're running */
if (err > 0) {
phydev->state = ETH_PHY_RUNNING;
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
} else if (0 == phydev->link_timeout--) {
needs_aneg = 1;
}
break;
case ETH_PHY_NOLINK:
err = phydev->drv->read_status(phydev);
if (err) {
break;
}
if (phydev->link) {
phydev->state = ETH_PHY_RUNNING;
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
}
break;
case ETH_PHY_FORCING:
err = genphy_update_link(phydev);
if (err) {
break;
}
if (phydev->link) {
phydev->state = ETH_PHY_RUNNING;
} else {
if (0 == phydev->link_timeout--) {
needs_aneg = 1;
}
}
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
break;
case ETH_PHY_RUNNING:
err = phydev->drv->read_status(phydev);
if (err) {
break;
}
if (phydev->link) {
phydev->state = ETH_PHY_RUNNING;
} else {
phydev->state = ETH_PHY_NOLINK;
}
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
break;
case ETH_PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
eth_phy_event(phydev, NETDEV_PHY_EVENT_LINK_CHANGED, phydev->link, 0);
}
break;
default:
break;
}
if(link != phydev->link || speed != phydev->speed || duplex != phydev->duplex){
SYSEVT_NEW_NETWORK_EVT(phydev->link ? SYSEVT_GMAC_LINK_UP : SYSEVT_GMAC_LINK_DOWN, phydev->speed);
}
if (needs_aneg) {
err = eth_phy_start_aneg(phydev);
}
}
/**
* @brief Handle the state machine thread
* @param phydev : target phy_device struct
* @retval None
*/
static int32 eth_phy_state_machine_thread(struct os_work *work)
{
struct _eth_phy_wkq *phydev = container_of(work, struct _eth_phy_wkq, os_work_phy);
eth_phy_state_machine(phydev->eth_phy_dev);
os_run_work_delay(work, 200);
return 0;
}
int32 eth_phy_open(struct ethernet_phy_device *phydev, struct ethernet_mdio_bus *mdio_bus, struct netdev *ndev)
{
eth_phy_wkq.eth_phy_dev = phydev;
uint32 feature_supproted = phydev->drv->features;
if (!phydev || !mdio_bus) {
return RET_ERR;
}
phydev->ndev = ndev;
ASSERT(ndev);
phydev->bus = mdio_bus;
ASSERT(mdio_bus);
if (eth_get_phy_device(phydev)) {
phydev->state = ETH_PHY_READY;
} else {
return RET_ERR;
}
/* attach the mac to the phy */
if (eth_phy_connect_direct(phydev) == RET_ERR) {
return RET_ERR;
}
/* Only support features that we can support */
phydev->advertising &= feature_supproted;
if (feature_supproted & SUPPORTED_Autoneg) {
phydev->autoneg = AUTONEG_ENABLE;
} else {
phydev->autoneg = AUTONEG_DISABLE;
}
/* Initial invalid value */
phydev->last_link = 0;
phydev->last_speed = 0;
phydev->last_duplex = -1;
/* start */
phydev->state = ETH_PHY_UP;
OS_WORK_INIT(&eth_phy_wkq.os_work_phy, eth_phy_state_machine_thread, 0);
os_run_work_delay(&eth_phy_wkq.os_work_phy, 1);
return RET_OK;
}
void eth_phy_close(struct ethernet_phy_device *phydev)
{
os_work_cancle(&eth_phy_wkq.os_work_phy, 1);
}
__init void eth_phy_attach(uint32 dev_id, struct ethernet_phy_device *phydev)
{
dev_register(dev_id, (struct dev_obj *)phydev);
}
/**
* @}
*/
/**
* @}
*/
/*************************** (C) COPYRIGHT 2018 HUGE-IC ***** END OF FILE *****/

View File

@@ -0,0 +1,580 @@
/**
******************************************************************************
* @file sdk/lib/ethernet_phy/eth_phy_device.c
* @author HUGE-IC Application Team
* @version V1.0.0
* @date 10-10-2018
* @brief Framework for finding and configuring PHYs.
* Also contains generic PHY driver
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2018 HUGE-IC</center></h2>
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "typesdef.h"
#include "errno.h"
#include "list.h"
#include "dev.h"
#include "osal/task.h"
#include "osal/string.h"
#include "hal/netdev.h"
#include "lib/net/ethphy/eth_mdio_bus.h"
#include "lib/net/ethphy/eth_phy.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @addtogroup NETWORK_PHY
* @{
*/
struct ethernet_phy_driver genphy_driver = {
.features = PHY_BASIC_FEATURES,
.config_init = genphy_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
};
/**
* @brief Convenience function for reading a given PHY register
* @param phydev : the phy_device struct
* @param reg : register number to read
* @retval Returns the data in the PHY register
*/
uint16 phy_read(struct ethernet_phy_device *phydev, uint16 reg) {
return phydev->bus->read(phydev->bus->priv, phydev->addr, reg);
}
/**
* @brief Convenience function for writing a given PHY register
* @param phydev : the phy_device struct
* @param reg : register number to write
* @param val : value to write to @reg
* @retval None
*/
void phy_write(struct ethernet_phy_device *phydev, uint16 reg, uint16 val) {
phydev->bus->write(phydev->bus->priv, phydev->addr, reg, val);
}
/**
* @brief A small helper function that translates ethtool advertisement
* settings to phy autonegotiation advertisements for the
* MII_ADVERTISE register.
* @param ethadv: the ethtool advertisement settings
* @retval MII_ADVERTISE register value
*/
static inline uint32 eth_phy_adv_to_mii_adv_t(uint32 ethadv) {
uint32 result = 0;
if(ethadv & ADVERTISED_10baseT_Half) {
result |= ADVERTISE_10HALF;
}
if(ethadv & ADVERTISED_10baseT_Full) {
result |= ADVERTISE_10FULL;
}
if(ethadv & ADVERTISED_100baseT_Half) {
result |= ADVERTISE_100HALF;
}
if(ethadv & ADVERTISED_100baseT_Full) {
result |= ADVERTISE_100FULL;
}
if(ethadv & ADVERTISED_Pause) {
result |= ADVERTISE_PAUSE_CAP;
}
if(ethadv & ADVERTISED_Asym_Pause) {
result |= ADVERTISE_PAUSE_ASYM;
}
return result;
}
/**
* @brief Initialize the phy_device structure.
* @param dev : the phy_device struct
* @retval None
*/
__init void eth_phy_device_create(struct ethernet_phy_device *dev)
{
dev->speed = 0;
dev->duplex = -1;
dev->pause = dev->asym_pause = 0;
dev->link = 1;
dev->autoneg = AUTONEG_ENABLE;
dev->state = ETH_PHY_DOWN;
}
/**
* @brief reads the specified addr for its ID.
* @param bus : the target MII bus
* @retval Returning 0 means success and returning other values means
* failure.
* @note In the case of a 802.3-c22 PHY, reads the ID registers of the
* PHY at @addr on the @bus, stores it in @phy_id and returns zero
* on success.
*/
__init static int eth_get_phy_id(struct ethernet_phy_device *phydev)
{
int phy_reg;
/* Grab the bits from PHYIR1, and put them
* in the upper half */
phy_reg = phy_read(phydev, MII_PHYSID1);
if(phy_reg < 0) {
return -1;
}
phydev->phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = phy_read(phydev, MII_PHYSID2);
if(phy_reg < 0) {
return -1;
}
phydev->phy_id |= (phy_reg & 0xffff);
//unvaild ID
switch(phydev->phy_id) {
case 0xFFFFFFFF:
case 0x00000000:
case 0x0000FFFF:
case 0xFFFF0000:
return -1;
}
return 0;
}
/**
* @brief reads the specified PHY device
* @param phydev : the phy_device struct
* @retval Return 1 to successfully initialize phy_device.
*/
__init uint8 eth_get_phy_device(struct ethernet_phy_device *phydev)
{
uint32 i;
//判断是否需要自适应查找地址
if(phydev->addr == PHY_ADAPTIVE_ADDR) {
for(i=1; i<=PHY_MAX_ADDR; i++) {
phydev->addr = i;
if(!eth_get_phy_id(phydev)) {
/* If the phy_id is mostly Fs, there is no device there */
if((phydev->phy_id & 0x1fffffff) != 0x1fffffff) {
break;
}
}
}
//not found
if(i > PHY_MAX_ADDR) {
return 0;
}
} else {
if(eth_get_phy_id(phydev)) {
return 0;
}
}
/* If the phy_id is mostly Fs, there is no device there */
if((phydev->phy_id & 0x1fffffff) == 0x1fffffff) {
return 0;
}
os_printf("eth phy id:%x\r\n", phydev->phy_id);
eth_phy_device_create(phydev);
return 1;
}
__init int genphy_config_init(struct ethernet_phy_device *phydev)
{
int val;
uint32 features;
/* For now, I'll claim that the generic driver supports
* all possible port types */
features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI |
SUPPORTED_FIBRE | SUPPORTED_BNC);
/* Do we support autonegotiation? */
val = phy_read(phydev, MII_BMSR);
if(val < 0) {
return val;
}
if(val & BMSR_ANEGCAPABLE) {
features |= SUPPORTED_Autoneg;
}
if(val & BMSR_100FULL) {
features |= SUPPORTED_100baseT_Full;
}
if(val & BMSR_100HALF) {
features |= SUPPORTED_100baseT_Half;
}
if(val & BMSR_10FULL) {
features |= SUPPORTED_10baseT_Full;
}
if(val & BMSR_10HALF) {
features |= SUPPORTED_10baseT_Half;
}
if(val & BMSR_ESTATEN) {
val = phy_read(phydev, MII_ESTATUS);
if(val < 0) {
return val;
}
if(val & ESTATUS_1000_TFULL) {
features |= SUPPORTED_1000baseT_Full;
}
if(val & ESTATUS_1000_THALF) {
features |= SUPPORTED_1000baseT_Half;
}
}
phydev->supported = features;
phydev->advertising = features;
return 0;
}
/**
* @brief attach a network device to a given PHY device pointer
* @param priv : PHY private structure pointer.
* @param phydev : Pointer to phy_device to attach
* @retval always return 1
* @note Called by drivers to attach to a particular PHY device. The
* phy_device is found, and properly hooked up to the phy_driver.
* If no driver is attached, then the genphy_driver is used. The
* phy_device is given a ptr to the attaching device, and given a
* callback for link status change. The phy_device is returned to
* the attaching driver.
*/
__init static int32 eth_phy_attach_direct(struct ethernet_phy_device *phydev)
{
phydev->state = ETH_PHY_READY;
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
return phydev->drv->config_init(phydev);
}
/**
* @brief connect an ethernet device to a specific phy_device
* @param phydev : the pointer to the phy device
* @param handler : callback function for state change notifications
* @retval Returns RET_OK if the PHY connection is successful
*/
__init int32 eth_phy_connect_direct(struct ethernet_phy_device *phydev)
{
int32 flag;
flag = eth_phy_attach_direct(phydev);
if(flag == RET_ERR) {
return RET_ERR;
}
eth_phy_start_machine(phydev);
return RET_OK;
}
/**
* @brief sanitize and advertise auto-negotiation parameters
* @param phydev : target phy_device struct
* @retval Returns < 0 on error, 0 if the PHY's advertisement hasn't
* changed, and > 0 if it has changed.
* @note Writes MII_ADVERTISE with the appropriate values, after
* sanitizing the values to make sure we only advertise what is
* supported.
*/
static int genphy_config_advert(struct ethernet_phy_device *phydev)
{
uint32 advertise;
int oldadv, adv;
int changed = 0;
/* Only allow advertising what
* this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
oldadv = adv = phy_read(phydev, MII_ADVERTISE);
if(adv < 0) {
return adv;
}
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
adv |= eth_phy_adv_to_mii_adv_t(advertise);
if(adv != oldadv) {
phy_write(phydev, MII_ADVERTISE, adv);
changed = 1;
}
/* Configure gigabit if it's supported */
// if (phydev->supported & (SUPPORTED_1000baseT_Half |
// SUPPORTED_1000baseT_Full)) {
// oldadv = adv = phy_read(phydev, MII_CTRL1000);
// if (adv < 0)
// return adv;
// adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
// adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
// if (adv != oldadv) {
// err = phy_write(phydev, MII_CTRL1000, adv);
// if (err < 0)
// return err;
// changed = 1;
// }
// }
return changed;
}
/**
* @brief configures/forces speed/duplex from @phydev
* @param phydev : target phy_device struct
* @retval None
* @note Configures MII_BMCR to force speed/duplex to the values in
* phydev. Assumes that the values are valid. Please see
* eth_phy_sanitize_settings().
*/
static void genphy_setup_forced(struct ethernet_phy_device *phydev)
{
int ctl = 0;
phydev->pause = phydev->asym_pause = 0;
if(SPEED_1000 == phydev->speed) {
ctl |= BMCR_SPEED1000;
} else if(SPEED_100 == phydev->speed) {
ctl |= BMCR_SPEED100;
}
if(DUPLEX_FULL == phydev->duplex) {
ctl |= BMCR_FULLDPLX;
}
phy_write(phydev, MII_BMCR, ctl);
}
/**
* @brief Enable and Restart Autonegotiation
* @param phydev : target phy_device struct
* @retval Returning 0 means the PHY supports auto-negotiation.
*/
int genphy_restart_aneg(struct ethernet_phy_device *phydev)
{
int ctl;
ctl = phy_read(phydev, MII_BMCR);
if(ctl < 0) {
return ctl;
}
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
/* Don't isolate the PHY if we're negotiating */
ctl &= ~(BMCR_ISOLATE);
phy_write(phydev, MII_BMCR, ctl);
return 0;
}
/**
* @brief restart auto-negotiation or write BMCR
* @param phydev : target phy_device struct
* @retval Returns the auto-negotiation configuration result.
* @note If auto-negotiation is enabled, we configure the advertising,
* and then restart auto-negotiation. If it is not enabled, then we
* write the BMCR
*/
int genphy_config_aneg(struct ethernet_phy_device *phydev)
{
int result;
if(AUTONEG_ENABLE != phydev->autoneg) {
genphy_setup_forced(phydev);
return 0;
}
result = genphy_config_advert(phydev);
if(result < 0) { /* error */
return result;
}
if(result == 0) {
/* Advertisement hasn't changed, but maybe aneg was never on to
* begin with? Or maybe phy was isolated? */
int ctl = phy_read(phydev, MII_BMCR);
if(ctl < 0) {
return ctl;
}
if(!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) {
result = 1; /* do restart aneg */
}
}
/* Only restart aneg if we are advertising something different
* than we were before. */
if(result > 0) {
result = genphy_restart_aneg(phydev);
}
return result;
}
/**
* @brief update link status in @phydev
* @param phydev : target phy_device struct
* @retval Returns the link status of the PHY.
* @note Update the value in phydev->link to reflect the current link
* value. In order to do this, we need to read the status register
* twice, keeping the second value.
*/
int genphy_update_link(struct ethernet_phy_device *phydev)
{
int status;
/* Do a fake read */
status = phy_read(phydev, MII_BMSR);
if(status < 0) {
return status;
}
/* Read link and autonegotiation status */
status = phy_read(phydev, MII_BMSR);
if(status < 0) {
return status;
}
if((status & BMSR_LSTATUS) == 0) {
phydev->link = 0;
} else {
phydev->link = 1;
}
return 0;
}
/**
* @brief check the link status and update current link state
* @param phydev : target phy_device struct
* @retval Returns 0 when the PHY has no errors.
* @note Check the link, then figure out the current state by comparing
* what we advertise with what the link partner advertises. Start
* by checking the gigabit possibilities, then move on to 10/100.
*/
int genphy_read_status(struct ethernet_phy_device *phydev)
{
int adv;
int err;
int lpa;
int lpagb = 0;
/* Update the link, but return if there
* was an error */
err = genphy_update_link(phydev);
if(err) {
return err;
}
if(AUTONEG_ENABLE == phydev->autoneg) {
if(phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) {
lpagb = phy_read(phydev, MII_STAT1000);
if(lpagb < 0) {
return lpagb;
}
adv = phy_read(phydev, MII_CTRL1000);
if(adv < 0) {
return adv;
}
lpagb &= adv << 2;
}
lpa = phy_read(phydev, MII_LPA);
if(lpa < 0) {
return lpa;
}
adv = phy_read(phydev, MII_ADVERTISE);
if(adv < 0) {
return adv;
}
lpa &= adv;
phydev->speed = SPEED_10;
phydev->duplex = DUPLEX_HALF;
phydev->pause = phydev->asym_pause = 0;
if(lpagb & (LPA_1000FULL | LPA_1000HALF)) {
phydev->speed = SPEED_1000;
if(lpagb & LPA_1000FULL) {
phydev->duplex = DUPLEX_FULL;
}
} else if(lpa & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
if(lpa & LPA_100FULL) {
phydev->duplex = DUPLEX_FULL;
}
} else {
if(lpa & LPA_10FULL) {
phydev->duplex = DUPLEX_FULL;
}
}
if(phydev->duplex == DUPLEX_FULL){
phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
}
} else {
int bmcr = phy_read(phydev, MII_BMCR);
if(bmcr < 0) {
return bmcr;
}
if(bmcr & BMCR_FULLDPLX) {
phydev->duplex = DUPLEX_FULL;
} else {
phydev->duplex = DUPLEX_HALF;
}
if(bmcr & BMCR_SPEED1000) {
phydev->speed = SPEED_1000;
} else if(bmcr & BMCR_SPEED100) {
phydev->speed = SPEED_100;
} else {
phydev->speed = SPEED_10;
}
phydev->pause = phydev->asym_pause = 0;
}
return 0;
}
/**
* @}
*/
/*************************** (C) COPYRIGHT 2018 HUGE-IC ***** END OF FILE *****/

205
sdk/lib/net/ethphy/mii.h Normal file
View File

@@ -0,0 +1,205 @@
/**
******************************************************************************
* @file Libraries/Protocol/net/include/uapi/linux/mii.h
* @author HUGE-IC Application Team
* @version V1.0.0
* @date 10-10-2018
* @brief definitions for MII-compatible transceivers
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2018 HUGE-IC</center></h2>
*
*
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __UAPI_LINUX_MII_H__
#define __UAPI_LINUX_MII_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @weakgroup NETWORK
* @{
*/
/** @defgroup NETWORK_MII MII Register
* @brief definitions for MII-compatible transceivers
* @{
*/
/** @defgroup MII_Exported_Constants Exported Constants
* @{
*/
/* Generic MII registers. */
#define MII_BMCR 0x00 /*!< Basic mode control register */
#define MII_BMSR 0x01 /*!< Basic mode status register */
#define MII_PHYSID1 0x02 /*!< PHYS ID 1 */
#define MII_PHYSID2 0x03 /*!< PHYS ID 2 */
#define MII_ADVERTISE 0x04 /*!< Advertisement control reg */
#define MII_LPA 0x05 /*!< Link partner ability reg */
#define MII_EXPANSION 0x06 /*!< Expansion register */
#define MII_CTRL1000 0x09 /*!< 1000BASE-T control */
#define MII_STAT1000 0x0a /*!< 1000BASE-T status */
#define MII_MMD_CTRL 0x0d /*!< MMD Access Control Register */
#define MII_MMD_DATA 0x0e /*!< MMD Access Data Register */
#define MII_ESTATUS 0x0f /*!< Extended Status */
#define MII_DCOUNTER 0x12 /*!< Disconnect counter */
#define MII_FCSCOUNTER 0x13 /*!< False carrier counter */
#define MII_NWAYTEST 0x14 /*!< N-way auto-neg test reg */
#define MII_RERRCOUNTER 0x15 /*!< Receive error counter */
#define MII_SREVISION 0x16 /*!< Silicon revision */
#define MII_RESV1 0x17 /*!< Reserved... */
#define MII_LBRERROR 0x18 /*!< Lpback, rx, bypass error */
#define MII_PHYADDR 0x19 /*!< PHY address */
#define MII_RESV2 0x1a /*!< Reserved... */
#define MII_TPISTATUS 0x1b /*!< TPI status for 10mbps */
#define MII_NCONFIG 0x1c /*!< Network interface config */
/* Basic mode control register. */
#define BMCR_RESV 0x003f /*!< Unused... */
#define BMCR_SPEED1000 0x0040 /*!< MSB of Speed (1000) */
#define BMCR_CTST 0x0080 /*!< Collision test */
#define BMCR_FULLDPLX 0x0100 /*!< Full duplex */
#define BMCR_ANRESTART 0x0200 /*!< Auto negotiation restart */
#define BMCR_ISOLATE 0x0400 /*!< Isolate data paths from MII */
#define BMCR_PDOWN 0x0800 /*!< Enable low power state */
#define BMCR_ANENABLE 0x1000 /*!< Enable auto negotiation */
#define BMCR_SPEED100 0x2000 /*!< Select 100Mbps */
#define BMCR_LOOPBACK 0x4000 /*!< TXD loopback bits */
#define BMCR_RESET 0x8000 /*!< Reset to default state */
/* Basic mode status register. */
#define BMSR_ERCAP 0x0001 /*!< Ext-reg capability */
#define BMSR_JCD 0x0002 /*!< Jabber detected */
#define BMSR_LSTATUS 0x0004 /*!< Link status */
#define BMSR_ANEGCAPABLE 0x0008 /*!< Able to do auto-negotiation */
#define BMSR_RFAULT 0x0010 /*!< Remote fault detected */
#define BMSR_ANEGCOMPLETE 0x0020 /*!< Auto-negotiation complete */
#define BMSR_RESV 0x00c0 /*!< Unused... */
#define BMSR_ESTATEN 0x0100 /*!< Extended Status in R15 */
#define BMSR_100HALF2 0x0200 /*!< Can do 100BASE-T2 HDX */
#define BMSR_100FULL2 0x0400 /*!< Can do 100BASE-T2 FDX */
#define BMSR_10HALF 0x0800 /*!< Can do 10mbps, half-duplex */
#define BMSR_10FULL 0x1000 /*!< Can do 10mbps, full-duplex */
#define BMSR_100HALF 0x2000 /*!< Can do 100mbps, half-duplex */
#define BMSR_100FULL 0x4000 /*!< Can do 100mbps, full-duplex */
#define BMSR_100BASE4 0x8000 /*!< Can do 100mbps, 4k packets */
/* Advertisement control register. */
#define ADVERTISE_SLCT 0x001f /*!< Selector bits */
#define ADVERTISE_CSMA 0x0001 /*!< Only selector supported */
#define ADVERTISE_10HALF 0x0020 /*!< Try for 10mbps half-duplex */
#define ADVERTISE_1000XFULL 0x0020 /*!< Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /*!< Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /*!< Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /*!< Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /*!< Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /*!< Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /*!< Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /*!< Try for 100mbps 4k packets */
#define ADVERTISE_PAUSE_CAP 0x0400 /*!< Try for pause */
#define ADVERTISE_PAUSE_ASYM 0x0800 /*!< Try for asymetric pause */
#define ADVERTISE_RESV 0x1000 /*!< Unused... */
#define ADVERTISE_RFAULT 0x2000 /*!< Say we can detect faults */
#define ADVERTISE_LPACK 0x4000 /*!< Ack link partners response */
#define ADVERTISE_NPAGE 0x8000 /*!< Next page bit */
#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
ADVERTISE_CSMA)
#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL)
/* Link partner ability register. */
#define LPA_SLCT 0x001f /*!< Same as advertise selector */
#define LPA_10HALF 0x0020 /*!< Can do 10mbps half-duplex */
#define LPA_1000XFULL 0x0020 /*!< Can do 1000BASE-X full-duplex */
#define LPA_10FULL 0x0040 /*!< Can do 10mbps full-duplex */
#define LPA_1000XHALF 0x0040 /*!< Can do 1000BASE-X half-duplex */
#define LPA_100HALF 0x0080 /*!< Can do 100mbps half-duplex */
#define LPA_1000XPAUSE 0x0080 /*!< Can do 1000BASE-X pause */
#define LPA_100FULL 0x0100 /*!< Can do 100mbps full-duplex */
#define LPA_1000XPAUSE_ASYM 0x0100 /*!< Can do 1000BASE-X pause asym */
#define LPA_100BASE4 0x0200 /*!< Can do 100mbps 4k packets */
#define LPA_PAUSE_CAP 0x0400 /*!< Can pause */
#define LPA_PAUSE_ASYM 0x0800 /*!< Can pause asymetrically */
#define LPA_RESV 0x1000 /*!< Unused... */
#define LPA_RFAULT 0x2000 /*!< Link partner faulted */
#define LPA_LPACK 0x4000 /*!< Link partner acked us */
#define LPA_NPAGE 0x8000 /*!< Next page bit */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/* Expansion register for auto-negotiation. */
#define EXPANSION_NWAY 0x0001 /*!< Can do N-way auto-nego */
#define EXPANSION_LCWP 0x0002 /*!< Got new RX page code word */
#define EXPANSION_ENABLENPAGE 0x0004 /*!< This enables npage words */
#define EXPANSION_NPCAPABLE 0x0008 /*!< Link partner supports npage */
#define EXPANSION_MFAULTS 0x0010 /*!< Multiple faults detected */
#define EXPANSION_RESV 0xffe0 /*!< Unused... */
#define ESTATUS_1000_TFULL 0x2000 /*!< Can do 1000BT Full */
#define ESTATUS_1000_THALF 0x1000 /*!< Can do 1000BT Half */
/* N-way test register. */
#define NWAYTEST_RESV1 0x00ff /*!< Unused... */
#define NWAYTEST_LOOPBACK 0x0100 /*!< Enable loopback for N-way */
#define NWAYTEST_RESV2 0xfe00 /*!< Unused... */
/* 1000BASE-T Control register */
#define ADVERTISE_1000FULL 0x0200 /*!< Advertise 1000BASE-T full duplex */
#define ADVERTISE_1000HALF 0x0100 /*!< Advertise 1000BASE-T half duplex */
#define CTL1000_AS_MASTER 0x0800
#define CTL1000_ENABLE_MASTER 0x1000
/* 1000BASE-T Status register */
#define LPA_1000LOCALRXOK 0x2000 /*!< Link partner local receiver status */
#define LPA_1000REMRXOK 0x1000 /*!< Link partner remote receiver status*/
#define LPA_1000FULL 0x0800 /*!< Link partner 1000BASE-T full duplex*/
#define LPA_1000HALF 0x0400 /*!< Link partner 1000BASE-T half duplex*/
/* Flow control flags */
#define FLOW_CTRL_TX 0x01
#define FLOW_CTRL_RX 0x02
/* MMD Access Control register fields */
#define MII_MMD_CTRL_DEVAD_MASK 0x1f /*!< Mask MMD DEVAD */
#define MII_MMD_CTRL_ADDR 0x0000 /*!< Address */
#define MII_MMD_CTRL_NOINCR 0x4000 /*!< no post increment */
#define MII_MMD_CTRL_INCR_RDWT 0x8000 /*!< post increment on reads & writes */
#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /*!< post increment on writes only */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif //__UAPI_LINUX_MII_H__
/*************************** (C) COPYRIGHT 2018 HUGE-IC ***** END OF FILE *****/

View File

@@ -0,0 +1,33 @@
#include "typesdef.h"
#include "list.h"
#include "errno.h"
#include "dev.h"
#include "osal/string.h"
#include "osal/semaphore.h"
#include "osal/mutex.h"
#include "osal/task.h"
#include "hal/netdev.h"
#include "lib/net/ethphy/eth_mdio_bus.h"
#include "lib/net/ethphy/eth_phy.h"
#include "lib/net/ethphy/phy/ip101g.h"
static int ip101g_config_init(struct ethernet_phy_device *phydev)
{
/* Disalbe 100BASE-TX EEE capability. Fix the problem of a large number of
* symbol errors in the communication between IP101GRI and Realtek RTL8168
* network card.
*/
phy_write(phydev, 13, 0x0007);
phy_write(phydev, 14, 0x003C);
phy_write(phydev, 13, 0x4007);
phy_write(phydev, 14, 0x0000);
return genphy_config_init(phydev);
}
struct ethernet_phy_driver ip101g_driver = {
.features = PHY_BASIC_FEATURES,
.config_init = ip101g_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
};