Files
luban-lite/bsp/artinchip/hal/mac/aic_phy.c
刘可亮 724d6bf65e v1.1.2
2025-01-08 19:12:06 +08:00

753 lines
22 KiB
C

/*
* Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <aic_core.h>
#include "aic_mac.h"
#include "aic_phy.h"
#define PHY_POLL_TASK_STACK_SIZE (1024)
#define PHY_POLL_TASK_PRIORITY (TCPIP_THREAD_PRIO-1)
#define PHY_POLL_TASK_INTERVAL_MS 1000
#define PHY_SETTING(s, d, b) \
{ \
.speed = SPEED_##s, .duplex = DUPLEX_##d, \
.bit = ETHTOOL_LINK_MODE_##b##_BIT \
}
static const struct phy_setting settings[] = {
#if 0
/* 400G */
PHY_SETTING(400000, FULL, 400000baseCR8_Full),
PHY_SETTING(400000, FULL, 400000baseKR8_Full),
PHY_SETTING(400000, FULL, 400000baseLR8_ER8_FR8_Full),
PHY_SETTING(400000, FULL, 400000baseDR8_Full),
PHY_SETTING(400000, FULL, 400000baseSR8_Full),
PHY_SETTING(400000, FULL, 400000baseCR4_Full),
PHY_SETTING(400000, FULL, 400000baseKR4_Full),
PHY_SETTING(400000, FULL, 400000baseLR4_ER4_FR4_Full),
PHY_SETTING(400000, FULL, 400000baseDR4_Full),
PHY_SETTING(400000, FULL, 400000baseSR4_Full),
/* 200G */
PHY_SETTING(200000, FULL, 200000baseCR4_Full),
PHY_SETTING(200000, FULL, 200000baseKR4_Full),
PHY_SETTING(200000, FULL, 200000baseLR4_ER4_FR4_Full),
PHY_SETTING(200000, FULL, 200000baseDR4_Full),
PHY_SETTING(200000, FULL, 200000baseSR4_Full),
PHY_SETTING(200000, FULL, 200000baseCR2_Full),
PHY_SETTING(200000, FULL, 200000baseKR2_Full),
PHY_SETTING(200000, FULL, 200000baseLR2_ER2_FR2_Full),
PHY_SETTING(200000, FULL, 200000baseDR2_Full),
PHY_SETTING(200000, FULL, 200000baseSR2_Full),
/* 100G */
PHY_SETTING(100000, FULL, 100000baseCR4_Full),
PHY_SETTING(100000, FULL, 100000baseKR4_Full),
PHY_SETTING(100000, FULL, 100000baseLR4_ER4_Full),
PHY_SETTING(100000, FULL, 100000baseSR4_Full),
PHY_SETTING(100000, FULL, 100000baseCR2_Full),
PHY_SETTING(100000, FULL, 100000baseKR2_Full),
PHY_SETTING(100000, FULL, 100000baseLR2_ER2_FR2_Full),
PHY_SETTING(100000, FULL, 100000baseDR2_Full),
PHY_SETTING(100000, FULL, 100000baseSR2_Full),
PHY_SETTING(100000, FULL, 100000baseCR_Full),
PHY_SETTING(100000, FULL, 100000baseKR_Full),
PHY_SETTING(100000, FULL, 100000baseLR_ER_FR_Full),
PHY_SETTING(100000, FULL, 100000baseDR_Full),
PHY_SETTING(100000, FULL, 100000baseSR_Full),
/* 56G */
PHY_SETTING(56000, FULL, 56000baseCR4_Full),
PHY_SETTING(56000, FULL, 56000baseKR4_Full),
PHY_SETTING(56000, FULL, 56000baseLR4_Full),
PHY_SETTING(56000, FULL, 56000baseSR4_Full),
/* 50G */
PHY_SETTING(50000, FULL, 50000baseCR2_Full),
PHY_SETTING(50000, FULL, 50000baseKR2_Full),
PHY_SETTING(50000, FULL, 50000baseSR2_Full),
PHY_SETTING(50000, FULL, 50000baseCR_Full),
PHY_SETTING(50000, FULL, 50000baseKR_Full),
PHY_SETTING(50000, FULL, 50000baseLR_ER_FR_Full),
PHY_SETTING(50000, FULL, 50000baseDR_Full),
PHY_SETTING(50000, FULL, 50000baseSR_Full),
/* 40G */
PHY_SETTING(40000, FULL, 40000baseCR4_Full),
PHY_SETTING(40000, FULL, 40000baseKR4_Full),
PHY_SETTING(40000, FULL, 40000baseLR4_Full),
PHY_SETTING(40000, FULL, 40000baseSR4_Full),
/* 25G */
PHY_SETTING(25000, FULL, 25000baseCR_Full),
PHY_SETTING(25000, FULL, 25000baseKR_Full),
PHY_SETTING(25000, FULL, 25000baseSR_Full),
/* 20G */
PHY_SETTING(20000, FULL, 20000baseKR2_Full),
PHY_SETTING(20000, FULL, 20000baseMLD2_Full),
/* 10G */
PHY_SETTING(10000, FULL, 10000baseCR_Full),
PHY_SETTING(10000, FULL, 10000baseER_Full),
PHY_SETTING(10000, FULL, 10000baseKR_Full),
PHY_SETTING(10000, FULL, 10000baseKX4_Full),
PHY_SETTING(10000, FULL, 10000baseLR_Full),
PHY_SETTING(10000, FULL, 10000baseLRM_Full),
PHY_SETTING(10000, FULL, 10000baseR_FEC),
PHY_SETTING(10000, FULL, 10000baseSR_Full),
PHY_SETTING(10000, FULL, 10000baseT_Full),
/* 5G */
PHY_SETTING(5000, FULL, 5000baseT_Full),
/* 2.5G */
PHY_SETTING(2500, FULL, 2500baseT_Full),
PHY_SETTING(2500, FULL, 2500baseX_Full),
#endif
/* 1G */
PHY_SETTING(1000, FULL, 1000baseKX_Full),
PHY_SETTING(1000, FULL, 1000baseT_Full),
PHY_SETTING(1000, HALF, 1000baseT_Half),
PHY_SETTING(1000, FULL, 1000baseT1_Full),
PHY_SETTING(1000, FULL, 1000baseX_Full),
/* 100M */
PHY_SETTING(100, FULL, 100baseT_Full),
PHY_SETTING(100, FULL, 100baseT1_Full),
PHY_SETTING(100, HALF, 100baseT_Half),
PHY_SETTING(100, HALF, 100baseFX_Half),
PHY_SETTING(100, FULL, 100baseFX_Full),
/* 10M */
PHY_SETTING(10, FULL, 10baseT_Full),
PHY_SETTING(10, HALF, 10baseT_Half),
};
aic_phy_device_t phy_device[MAX_ETH_MAC_PORT];
extern aicmac_config_t mac_config[MAX_ETH_MAC_PORT];
extern aicmac_netif_t aic_netif;
int aicphy_sw_reset(uint32_t port)
{
uint16_t tmpreg = 0;
uint32_t timeout = 0;
int ret = 0;
/* Get the PHY configuration to update it */
ret = aicmac_write_phy_reg(port, MII_BMCR, BMCR_RESET);
if (ret)
return ret;
/* Check for the Busy flag */
do {
timeout++;
ret = aicmac_read_phy_reg(port, MII_BMCR, &tmpreg);
if (ret)
return ret;
} while ((tmpreg & BMCR_RESET) && (timeout < (uint32_t)PHY_WRITE_TO));
if (timeout == PHY_WRITE_TO) {
pr_err("aicmac software reset timeout.\n");
ret = ETH_ERROR;
}
return ret;
}
int aicphy_set_loopback(uint32_t port, bool en)
{
uint16_t tmpreg = 0;
int ret = 0;
/* Get the PHY configuration to update it */
ret = aicmac_read_phy_reg(port, MII_BMCR, &tmpreg);
if (ret)
return ret;
if (en)
tmpreg |= BMCR_LOOPBACK;
else
tmpreg &= ~BMCR_LOOPBACK;
ret = aicmac_write_phy_reg(port, MII_BMCR, tmpreg);
return ret;
}
static inline void linkmode_mod_bit(int nr, u64 *addr, int set)
{
if (set)
*addr |= (1ULL << nr);
else
*addr &= ~(1ULL << nr);
}
static inline int linkmode_test_bit(int nr, u64 *addr)
{
return (*addr & (1ULL << nr));
}
static inline int test_bit(int nr, u64 *addr)
{
return (*addr & (1ULL << nr));
}
static inline u16 linkmode_adv_to_mii_adv_t(u64 *advertising)
{
u16 result = 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, advertising))
result |= ADVERTISE_10HALF;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising))
result |= ADVERTISE_10FULL;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertising))
result |= ADVERTISE_100HALF;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising))
result |= ADVERTISE_100FULL;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
result |= ADVERTISE_PAUSE_CAP;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
result |= ADVERTISE_PAUSE_ASYM;
return result;
}
static inline u16 linkmode_adv_to_mii_ctrl1000_t(u64 *advertising)
{
u16 result = 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertising))
result |= ADVERTISE_1000HALF;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertising))
result |= ADVERTISE_1000FULL;
return result;
}
static inline void mii_stat1000_mod_linkmode_lpa_t(u64 *advertising, u16 lpa)
{
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, advertising,
lpa & LPA_1000HALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, advertising,
lpa & LPA_1000FULL);
}
static inline void mii_adv_mod_linkmode_adv_t(u64 *advertising, u16 adv)
{
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, advertising,
adv & ADVERTISE_10HALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, advertising,
adv & ADVERTISE_10FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, advertising,
adv & ADVERTISE_100HALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, advertising,
adv & ADVERTISE_100FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
adv & ADVERTISE_PAUSE_CAP);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising,
adv & ADVERTISE_PAUSE_ASYM);
}
static inline void mii_lpa_mod_linkmode_lpa_t(u64 *lp_advertising, u16 lpa)
{
mii_adv_mod_linkmode_adv_t(lp_advertising, lpa);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, lp_advertising,
lpa & LPA_LPACK);
}
int phy_modify(uint32_t port, u32 regnum, u16 mask, u16 set)
{
uint16_t val = 0;
uint16_t new = 0;
int err = 0;
err = aicmac_read_phy_reg(port, regnum, &val);
if (err)
return ETH_ERROR;
new = (val & ~mask) | set;
if (new == val)
return ETH_SUCCESS;
err = aicmac_write_phy_reg(port, regnum, val);
if (err)
return ETH_ERROR;
return ETH_SUCCESS;
}
int aicphy_read_abilities(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
u16 val = 0;
int err = 0;
/*
linkmode_set_bit_array(phy_basic_ports_array,
ARRAY_SIZE(phy_basic_ports_array),
phydev->supported);
*/
//linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported, 1);
linkmode_mod_bit(ETHTOOL_LINK_MODE_TP_BIT, phydev->supported, 1);
linkmode_mod_bit(ETHTOOL_LINK_MODE_MII_BIT, phydev->supported, 1);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported, 1);
err = aicmac_read_phy_reg(port, MII_BMSR, &val);
if (err)
return ETH_ERROR;
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported,
val & BMSR_ANEGCAPABLE);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported,
val & BMSR_100FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, phydev->supported,
val & BMSR_100HALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, phydev->supported,
val & BMSR_10FULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, phydev->supported,
val & BMSR_10HALF);
if (val & BMSR_ESTATEN) {
err = aicmac_read_phy_reg(port, MII_ESTATUS, &val);
if (err)
return ETH_ERROR;
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported, val & ESTATUS_1000_TFULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->supported, val & ESTATUS_1000_THALF);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
phydev->supported, val & ESTATUS_1000_XFULL);
}
/* Check phy abilities */
if (!linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported))
phydev->autoneg = 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
phydev->supported))
phydev->is_gigabit_capable = 1;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported))
phydev->is_gigabit_capable = 1;
return ETH_SUCCESS;
}
int aicphy_config_advert(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
int err = 0;
u16 bmsr = 0;
u16 adv = 0;
/* Only allow advertising what this PHY supports */
/* linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported);*/
phydev->advertising[0] = phydev->supported[0];
adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
/* Setup standard advertisement */
err = phy_modify(port, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM,
adv);
if (err)
return err;
err = aicmac_read_phy_reg(port, MII_BMSR, &bmsr);
if (err)
return ETH_ERROR;
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
* 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
* logical 1.
*/
if (!(bmsr & BMSR_ESTATEN))
return ETH_SUCCESS;
adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
err = phy_modify(port, MII_CTRL1000,
ADVERTISE_1000FULL | ADVERTISE_1000HALF, adv);
if (err)
return err;
return ETH_SUCCESS;
}
int aicphy_restart_aneg(uint32_t port)
{
/* Don't isolate the PHY if we're negotiating */
return phy_modify(port, MII_BMCR, BMCR_ISOLATE,
BMCR_ANENABLE | BMCR_ANRESTART);
}
int aicphy_setup_forced(uint32_t port)
{
aicmac_config_t *config = &mac_config[port];
u16 ctl = 0;
if (SPEED_1000 == config->max_speed)
ctl |= BMCR_SPEED1000;
else if (SPEED_100 == config->max_speed)
ctl |= BMCR_SPEED100;
if (config->duplex)
ctl |= BMCR_FULLDPLX;
return phy_modify(port, MII_BMCR,
~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
}
int aicphy_config_aneg(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
int err;
if (!phydev->autoneg) {
return aicphy_setup_forced(port);
} else {
err = aicphy_config_advert(port);
if (err)
return err;
err = aicphy_restart_aneg(port);
if (err)
return err;
}
return ETH_SUCCESS;
}
int aicphy_read_lpa(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
u16 lpa, lpagb, adv;
int err = 0;
if (phydev->autoneg) {
if (!phydev->autoneg_complete) {
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
return 0;
}
if (phydev->is_gigabit_capable) {
err = aicmac_read_phy_reg(port, MII_STAT1000, &lpagb);
if (err)
return ETH_ERROR;
if (lpagb & LPA_1000MSFAIL) {
err = aicmac_read_phy_reg(port, MII_CTRL1000, &adv);
if (err)
return ETH_ERROR;
if (adv & CTL1000_ENABLE_MASTER)
pr_err(
"Master/Slave resolution failed, maybe conflicting manual settings?\n");
else
pr_err("Master/Slave resolution failed\n");
return ETH_ERROR;
}
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, lpagb);
}
err = aicmac_read_phy_reg(port, MII_LPA, &lpa);
if (err)
return ETH_ERROR;
mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
} else {
phydev->lp_advertising[0] = 0;
}
return ETH_SUCCESS;
}
void aicphy_resolve_aneg_pause(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
if (phydev->duplex) {
if(linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
phydev->lp_advertising))
phydev->pause = 1;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->lp_advertising))
phydev->asym_pause = 1;
}
}
void aicphy_resolve_aneg_linkmode(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
u64 common = 0;
int i;
#ifdef PHY_DEBUG
uint16_t tmpreg = 0;
pr_info("%s:\n", __func__);
for (i = 0; i < 0x20; i++) {
aicmac_read_phy_reg(port, i, &tmpreg);
pr_info("0x%x: 0x%x\n", i, tmpreg);
}
#endif
/* local advertising AND link partner advertising */
phydev->advertising[0] = phydev->supported[0];
common = phydev->advertising[0] & phydev->lp_advertising[0];
pr_debug("common = 0x%llx, supported = 0x%llx, advertising = 0x%llx, lp_advertising = 0x%llx.\n",
common, phydev->supported[0], phydev->advertising[0], phydev->lp_advertising[0]);
for (i = 0; i < ARRAY_SIZE(settings); i++)
if (test_bit(settings[i].bit, &common)) {
phydev->speed = settings[i].speed;
phydev->duplex = settings[i].duplex;
pr_debug("setting %d: speed %dM, duplex %d.\n", i, phydev->speed, phydev->duplex);
break;
}
aicphy_resolve_aneg_pause(port);
}
int aicphy_read_status_fixed(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
u16 bmcr = 0;
int err;
err = aicmac_read_phy_reg(port, MII_BMCR, &bmcr);
if (err)
return ETH_ERROR;
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;
return 0;
}
int aicphy_update_link(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
u16 status = 0;
u16 bmcr = 0;
int err;
err = aicmac_read_phy_reg(port, MII_BMCR, &bmcr);
if (err)
return ETH_ERROR;
/* Autoneg is being started, therefore disregard BMSR value and
* report link as down.
*/
if (bmcr & BMCR_ANRESTART)
goto done;
/* Read link and autonegotiation status */
err = aicmac_read_phy_reg(port, MII_BMSR, &status);
if (err)
return ETH_ERROR;
done:
phydev->link = status & BMSR_LSTATUS ? 1 : 0;
phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
/* Consider the case that autoneg was started and "aneg complete"
* bit has been reset, but "link up" bit not yet.
*/
if (phydev->autoneg && !phydev->autoneg_complete)
phydev->link = 0;
return ETH_SUCCESS;
}
int aicphy_read_status(uint32_t port)
{
aic_phy_device_t *phydev = &phy_device[port];
int old_link = phydev->link;
int err;
/* Update the link, but return if there was an error */
err = aicphy_update_link(port);
if (err)
return ETH_ERROR;
/* why bother the PHY if nothing can have changed */
if (!(phydev->link) || (old_link == phydev->link))
return ETH_SUCCESS;
phydev->speed = 0;
phydev->duplex = 0;
phydev->pause = 0;
phydev->asym_pause = 0;
err = aicphy_read_lpa(port);
if (err)
return err;
if (phydev->autoneg && phydev->autoneg_complete) {
aicphy_resolve_aneg_linkmode(port);
} else if (!phydev->autoneg) {
err = aicphy_read_status_fixed(port);
if (err)
return err;
}
return ETH_SUCCESS;
}
void aic_phy_poll(struct netif *netif)
{
aicmac_netif_t *aic_netif = (aicmac_netif_t *)netif;
uint32_t port = aic_netif->port;
aic_phy_device_t *phydev = &phy_device[port];
static int old_link = 0;
int err;
/* Pool phy satus */
err = aicphy_read_status(port);
if (err) {
pr_err("%s fail.\n", __func__);
return;
}
/* Phy link status not change */
if (old_link == phydev->link)
return;
old_link = phydev->link;
/* Phy link status change: DOWN -> UP */
if (phydev->link) {
pr_info(" Port %d link UP! %s mode: speed %dM, %s duplex, flow control %s.\n",
(int)port,
(phydev->autoneg ? "autoneg" : "fixed"),
phydev->speed,
(phydev->duplex ? "full" : "half"),
(phydev->pause ? "on" : "off"));
/* Config mac base on autoneg result */
if (phydev->autoneg) {
aicmac_set_mac_speed(port, phydev->speed);
aicmac_set_mac_duplex(port, phydev->duplex);
aicmac_set_mac_pause(port, phydev->pause);
}
/* Enable MAC and DMA transmission and reception */
aicmac_start(port);
/* Netif set phy linkup */
netif_set_link_up(netif);
/* Phy link status change: UP -> DOWN */
} else {
pr_info(" Port %d link DOWN!\n", (int)port);
/* Disable MAC and DMA transmission and reception */
aicmac_stop(port);
/* Netif set phy linkdown */
netif_set_link_down(netif);
}
}
void aicphy_poll_thread(void *pvParameters)
{
aicmac_netif_t *aic_netif = (aicmac_netif_t *)pvParameters;
uint32_t port = aic_netif->port;
struct netif *netif = &aic_netif->netif;
aic_phy_device_t *phydev = &phy_device[port];
int old_link = 0;
int err;
while(1) {
/* Sleep */
aicos_msleep(PHY_POLL_TASK_INTERVAL_MS);
/* Pool phy satus */
err = aicphy_read_status(port);
if (err) {
pr_err("%s fail.\n", __func__);
continue;
}
/* Phy link status not change */
if (old_link == phydev->link)
continue;
old_link = phydev->link;
/* Phy link status change: DOWN -> UP */
if (phydev->link) {
pr_info(" Port %d link UP! %s mode: speed %dM, %s duplex, flow control %s.\n",
(int)port,
(phydev->autoneg ? "autoneg" : "fixed"),
phydev->speed,
(phydev->duplex ? "full" : "half"),
(phydev->pause ? "on" : "off"));
/* Config mac base on autoneg result */
if (phydev->autoneg) {
aicmac_set_mac_speed(port, phydev->speed);
aicmac_set_mac_duplex(port, phydev->duplex);
aicmac_set_mac_pause(port, phydev->pause);
}
/* Enable MAC and DMA transmission and reception */
aicmac_start(port);
/* Netif set phy linkup */
netif_set_link_up(netif);
/* Phy link status change: UP -> DOWN */
} else {
pr_info(" Port %d link DOWN!\n", (int)port);
/* Disable MAC and DMA transmission and reception */
aicmac_stop(port);
/* Netif set phy linkdown */
netif_set_link_down(netif);
}
}
}
int aicphy_init(aicmac_netif_t *aic_netif)
{
uint32_t port = aic_netif->port;
aicmac_config_t *config = &mac_config[port];
aic_phy_device_t *phydev = &phy_device[port];
phydev->autoneg = config->autonegotiation;
#ifdef PHY_DEBUG
uint16_t tmpreg = 0;
int i = 0;
pr_info("%s:\n", __func__);
for (i = 0; i < 0x20; i++) {
aicmac_read_phy_reg(port, i, &tmpreg);
pr_info("0x%x: 0x%x\n", i, tmpreg);
}
#endif
//aicphy_sw_reset(port);
aicphy_read_abilities(port);
aicphy_config_aneg(port);
#if !NO_SYS
/* create the task that handles the ETH_MAC */
aicos_thread_create("eth_phy_poll", PHY_POLL_TASK_STACK_SIZE,
PHY_POLL_TASK_PRIORITY, aicphy_poll_thread, aic_netif);
#endif
return ETH_SUCCESS;
}