rt-thread-official/bsp/loongson/ls2kdev/drivers/net/mii.c

141 lines
4.1 KiB
C

/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-24 chinesebear first version
*/
#include "mii.h"
static inline 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;
}
static int mii_check_gmii_support(struct mii_if_info *mii)
{
int reg;
reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (reg & BMSR_ESTATEN)
{
reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
return 1;
}
return 0;
}
static int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct synopGMACNetworkAdapter *dev = mii->dev;
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(dev, mii->phy_id, MII_ADVERTISE);
if (mii->supports_gmii)
advert2 = mii->mdio_read(dev, 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(dev, mii->phy_id, MII_BMCR);
lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
if (mii->supports_gmii)
{
bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
lpa2 = mii->mdio_read(dev, 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;
}
static int mii_link_ok(struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
return 1;
return 0;
}