145 lines
4.3 KiB
C
145 lines
4.3 KiB
C
|
/**************************************************************************//**
|
||
|
*
|
||
|
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
||
|
*
|
||
|
* SPDX-License-Identifier: Apache-2.0
|
||
|
*
|
||
|
* Change Logs:
|
||
|
* Date Author Notes
|
||
|
* 2021-07-23 Wayne First version
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include "mii.h"
|
||
|
|
||
|
unsigned int mii_nway_result(unsigned int negotiated)
|
||
|
{
|
||
|
unsigned int ret;
|
||
|
|
||
|
if (negotiated & LPA_100FULL)
|
||
|
ret = LPA_100FULL;
|
||
|
else if (negotiated & LPA_100BASE4)
|
||
|
ret = LPA_100BASE4;
|
||
|
else if (negotiated & LPA_100HALF)
|
||
|
ret = LPA_100HALF;
|
||
|
else if (negotiated & LPA_10FULL)
|
||
|
ret = LPA_10FULL;
|
||
|
else
|
||
|
ret = LPA_10HALF;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int mii_check_gmii_support(struct mii_if_info *mii)
|
||
|
{
|
||
|
int reg;
|
||
|
|
||
|
reg = mii->mdio_read(mii->adapter, mii->phy_id, MII_BMSR);
|
||
|
if (reg & BMSR_ESTATEN)
|
||
|
{
|
||
|
reg = mii->mdio_read(mii->adapter, mii->phy_id, MII_ESTATUS);
|
||
|
if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
|
||
|
{
|
||
|
void *adapter = mii->adapter;
|
||
|
u32 advert, bmcr, lpa, nego;
|
||
|
u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
|
||
|
|
||
|
ecmd->supported =
|
||
|
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
|
||
|
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
|
||
|
SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
|
||
|
if (mii->supports_gmii)
|
||
|
ecmd->supported |= SUPPORTED_1000baseT_Half |
|
||
|
SUPPORTED_1000baseT_Full;
|
||
|
|
||
|
/* only supports twisted-pair */
|
||
|
ecmd->port = PORT_MII;
|
||
|
|
||
|
/* only supports internal transceiver */
|
||
|
ecmd->transceiver = XCVR_INTERNAL;
|
||
|
|
||
|
/* this isn't fully supported at higher layers */
|
||
|
ecmd->phy_address = mii->phy_id;
|
||
|
|
||
|
ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
|
||
|
advert = mii->mdio_read(adapter, mii->phy_id, MII_ADVERTISE);
|
||
|
if (mii->supports_gmii)
|
||
|
advert2 = mii->mdio_read(adapter, mii->phy_id, MII_CTRL1000);
|
||
|
|
||
|
if (advert & ADVERTISE_10HALF)
|
||
|
ecmd->advertising |= ADVERTISED_10baseT_Half;
|
||
|
if (advert & ADVERTISE_10FULL)
|
||
|
ecmd->advertising |= ADVERTISED_10baseT_Full;
|
||
|
if (advert & ADVERTISE_100HALF)
|
||
|
ecmd->advertising |= ADVERTISED_100baseT_Half;
|
||
|
if (advert & ADVERTISE_100FULL)
|
||
|
ecmd->advertising |= ADVERTISED_100baseT_Full;
|
||
|
if (advert2 & ADVERTISE_1000HALF)
|
||
|
ecmd->advertising |= ADVERTISED_1000baseT_Half;
|
||
|
if (advert2 & ADVERTISE_1000FULL)
|
||
|
ecmd->advertising |= ADVERTISED_1000baseT_Full;
|
||
|
|
||
|
bmcr = mii->mdio_read(adapter, mii->phy_id, MII_BMCR);
|
||
|
lpa = mii->mdio_read(adapter, mii->phy_id, MII_LPA);
|
||
|
if (mii->supports_gmii)
|
||
|
{
|
||
|
bmcr2 = mii->mdio_read(adapter, mii->phy_id, MII_CTRL1000);
|
||
|
lpa2 = mii->mdio_read(adapter, mii->phy_id, MII_STAT1000);
|
||
|
}
|
||
|
if (bmcr & BMCR_ANENABLE)
|
||
|
{
|
||
|
ecmd->advertising |= ADVERTISED_Autoneg;
|
||
|
ecmd->autoneg = AUTONEG_ENABLE;
|
||
|
|
||
|
nego = mii_nway_result(advert & lpa);
|
||
|
if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
|
||
|
(lpa2 >> 2))
|
||
|
ecmd->speed = SPEED_1000;
|
||
|
else if (nego == LPA_100FULL || nego == LPA_100HALF)
|
||
|
ecmd->speed = SPEED_100;
|
||
|
else
|
||
|
ecmd->speed = SPEED_10;
|
||
|
if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
|
||
|
nego == LPA_10FULL)
|
||
|
{
|
||
|
ecmd->duplex = DUPLEX_FULL;
|
||
|
mii->full_duplex = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ecmd->duplex = DUPLEX_HALF;
|
||
|
mii->full_duplex = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ecmd->autoneg = AUTONEG_DISABLE;
|
||
|
|
||
|
ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
|
||
|
(bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
|
||
|
(bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
|
||
|
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
|
||
|
}
|
||
|
|
||
|
/* ignore maxtxpkt, maxrxpkt for now */
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mii_link_ok(struct mii_if_info *mii)
|
||
|
{
|
||
|
/* first, a dummy read, needed to latch some MII phys */
|
||
|
mii->mdio_read(mii->adapter, mii->phy_id, MII_BMSR);
|
||
|
if (mii->mdio_read(mii->adapter, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
|
||
|
return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|