1 /*
2  * Copyright (c) 2006-2020, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-08-24     chinesebear  first version
9  */
10 #include "mii.h"
11 
mii_nway_result(unsigned int negotiated)12 static inline unsigned int mii_nway_result(unsigned int negotiated)
13 {
14     unsigned int ret;
15 
16     if (negotiated & LPA_100FULL)
17         ret = LPA_100FULL;
18     else if (negotiated & LPA_100BASE4)
19         ret = LPA_100BASE4;
20     else if (negotiated & LPA_100HALF)
21         ret = LPA_100HALF;
22     else if (negotiated & LPA_10FULL)
23         ret = LPA_10FULL;
24     else
25         ret = LPA_10HALF;
26 
27     return ret;
28 }
29 
mii_check_gmii_support(struct mii_if_info * mii)30 static int mii_check_gmii_support(struct mii_if_info *mii)
31 {
32     int reg;
33 
34     reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
35     if (reg & BMSR_ESTATEN)
36     {
37         reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
38         if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
39             return 1;
40     }
41 
42     return 0;
43 }
44 
mii_ethtool_gset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)45 static int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
46 {
47     struct synopGMACNetworkAdapter *dev = mii->dev;
48     u32 advert, bmcr, lpa, nego;
49     u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
50 
51     ecmd->supported =
52         (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
53          SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
54          SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
55     if (mii->supports_gmii)
56         ecmd->supported |= SUPPORTED_1000baseT_Half |
57                            SUPPORTED_1000baseT_Full;
58 
59     /* only supports twisted-pair */
60     ecmd->port = PORT_MII;
61 
62     /* only supports internal transceiver */
63     ecmd->transceiver = XCVR_INTERNAL;
64 
65     /* this isn't fully supported at higher layers */
66     ecmd->phy_address = mii->phy_id;
67 
68     ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
69     advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
70     if (mii->supports_gmii)
71         advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
72 
73     if (advert & ADVERTISE_10HALF)
74         ecmd->advertising |= ADVERTISED_10baseT_Half;
75     if (advert & ADVERTISE_10FULL)
76         ecmd->advertising |= ADVERTISED_10baseT_Full;
77     if (advert & ADVERTISE_100HALF)
78         ecmd->advertising |= ADVERTISED_100baseT_Half;
79     if (advert & ADVERTISE_100FULL)
80         ecmd->advertising |= ADVERTISED_100baseT_Full;
81     if (advert2 & ADVERTISE_1000HALF)
82         ecmd->advertising |= ADVERTISED_1000baseT_Half;
83     if (advert2 & ADVERTISE_1000FULL)
84         ecmd->advertising |= ADVERTISED_1000baseT_Full;
85 
86     bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
87     lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
88     if (mii->supports_gmii)
89     {
90         bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
91         lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
92     }
93     if (bmcr & BMCR_ANENABLE)
94     {
95         ecmd->advertising |= ADVERTISED_Autoneg;
96         ecmd->autoneg = AUTONEG_ENABLE;
97 
98         nego = mii_nway_result(advert & lpa);
99         if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
100                 (lpa2 >> 2))
101             ecmd->speed = SPEED_1000;
102         else if (nego == LPA_100FULL || nego == LPA_100HALF)
103             ecmd->speed = SPEED_100;
104         else
105             ecmd->speed = SPEED_10;
106         if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
107                 nego == LPA_10FULL)
108         {
109             ecmd->duplex = DUPLEX_FULL;
110             mii->full_duplex = 1;
111         }
112         else
113         {
114             ecmd->duplex = DUPLEX_HALF;
115             mii->full_duplex = 0;
116         }
117     }
118     else
119     {
120         ecmd->autoneg = AUTONEG_DISABLE;
121 
122         ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
123                         (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
124                        (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
125         ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
126     }
127 
128     /* ignore maxtxpkt, maxrxpkt for now */
129 
130     return 0;
131 }
132 
mii_link_ok(struct mii_if_info * mii)133 static int mii_link_ok(struct mii_if_info *mii)
134 {
135     /* first, a dummy read, needed to latch some MII phys */
136     mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
137     if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
138         return 1;
139     return 0;
140 }
141