151 lines
4.3 KiB
C
151 lines
4.3 KiB
C
/*
|
|
* File : mii.c
|
|
* This file is part of RT-Thread RTOS
|
|
* COPYRIGHT (C) chinesebear
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* 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;
|
|
}
|
|
|