• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "eth_phy.h"
17 #include "linux/kernel.h"
18 #include "hieth.h"
19 #include "mdio.h"
20 #include "stdio.h"
21 
22 #define WAIT_PHY_AUTO_NEG_TIMES 25
23 
HiethGetPhyStat(struct HiethNetdevLocal * ld,EthPhyAccess * phyAccess,uint32_t * state)24 bool HiethGetPhyStat(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess, uint32_t *state)
25 {
26     int32_t phyState;
27     int32_t i;
28 
29     *state = 0;
30     phyState = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR);
31     if (phyState < 0) {
32         return false;
33     }
34     if (!((uint32_t)phyState & BMSR_AN_COMPLETE)) {
35         HDF_LOGE("waiting for auto-negotiation completed!");
36         for (i = 0; i < WAIT_PHY_AUTO_NEG_TIMES; i++) {
37             phyState = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR);
38             if ((phyState >= 0) && ((uint32_t)phyState & BMSR_AN_COMPLETE)) {
39                 break;
40             }
41             msleep(10);
42         }
43     }
44     if ((uint32_t)phyState & BMSR_AN_COMPLETE) {
45         if ((uint32_t)phyState & BMSR_LINK) {
46             *state |= ETH_PHY_STAT_LINK;
47         }
48         return true;
49     }
50     return false;
51 }
52 
MiiphyLink(struct HiethNetdevLocal * ld,EthPhyAccess * phyAccess)53 int32_t MiiphyLink(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess)
54 {
55     int32_t reg;
56 
57     reg = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR);
58     if (reg < 0) {
59         HDF_LOGE("PHY_BMSR read failed, assuming no link");
60         return HDF_SUCCESS;
61     }
62 
63     /* Determine if a link is active */
64     if (((uint32_t)reg & BMSR_LINK) != 0) {
65         return HDF_FAILURE;
66     } else {
67         return HDF_SUCCESS;
68     }
69 }
70 
71 /*****************************************************************************
72  *
73  * Return 1 if PHY supports 1000BASE-X, 0 if PHY supports 10BASE-T/100BASE-TX/
74  * 1000BASE-T, or on error.
75  */
MiiphyIs1000baseX(struct HiethNetdevLocal * ld,EthPhyAccess * phyAccess)76 static int32_t MiiphyIs1000baseX(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess)
77 {
78     int32_t reg;
79 
80     reg = HiethMdioRead(ld, phyAccess->phyAddr, PHY_EXSR);
81     if (reg < 0) {
82         HDF_LOGE("PHY_EXSR read failed, assume no 1000BASE-X");
83         return HDF_SUCCESS;
84     }
85     return ((uint32_t)reg & (EXSR_1000XF | EXSR_1000XH)) != 0;
86 }
87 
88 /*****************************************************************************
89  *
90  * Determine the ethernet speed (10/100/1000).  Return 10 on error.
91  */
MiiphySpeed(struct HiethNetdevLocal * ld,EthPhyAccess * phyAccess)92 int32_t MiiphySpeed(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess)
93 {
94     int32_t bmcr, anlpar;
95     int32_t btsr, val;
96 
97     val = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR);
98     if (val < 0) {
99         HDF_LOGE("PHY 1000BT status[read PHY_BMSR]\n");
100         return PHY_SPEED_10;
101     }
102 
103     if ((uint32_t)val & BMSR_ESTATEN) {
104         if (MiiphyIs1000baseX(ld, phyAccess)) {
105             return PHY_SPEED_1000;
106         }
107         btsr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_1000BTSR);
108         if (btsr < 0) {
109             HDF_LOGE("PHY 1000BT status[read PHY_1000BTSR]\n");
110             return PHY_SPEED_10;
111         }
112         if (btsr != 0xFFFF && ((uint32_t)btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
113             return PHY_SPEED_1000;
114         }
115     }
116 
117     /* Check Basic Management Control Register first. */
118     bmcr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMCR);
119     if (bmcr < 0) {
120         HDF_LOGE("PHY speed read failed[read PHY_BMCR]");
121         return PHY_SPEED_10;
122     }
123 
124     if ((uint32_t)bmcr & BMCR_AN_ENABLE) {
125         anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR);
126         if (anlpar < 0) {
127             HDF_LOGE("PHY AN speed failed[anlpar]");
128             return PHY_SPEED_10;
129         }
130         return ((uint32_t)anlpar & ANLPAR_100) ? PHY_SPEED_100 : PHY_SPEED_10;
131     }
132     return ((uint32_t)bmcr & BMCR_SPEED100) ? PHY_SPEED_100 : PHY_SPEED_10;
133 }
134 
135 /*
136  * Determine full/half duplex.  Return half on error.
137  */
MiiphyDuplex(struct HiethNetdevLocal * ld,EthPhyAccess * phyAccess)138 int32_t MiiphyDuplex(struct HiethNetdevLocal *ld, EthPhyAccess *phyAccess)
139 {
140     int32_t bmcr, anlpar, val;
141     val = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMSR);
142     if (val < 0) {
143         HDF_LOGE("PHY duplex read failed");
144         return PHY_DUPLEX_HALF;
145     }
146 
147     if ((uint32_t)val & BMSR_ESTATEN) {
148         int32_t btsr;
149         /* Check for 1000BASE-X */
150         if (MiiphyIs1000baseX(ld, phyAccess)) {
151             /* 1000BASE-X */
152             anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR);
153             if (anlpar < 0) {
154                 HDF_LOGE("1000BASE-X PHY AN duplex failed");
155                 return PHY_DUPLEX_HALF;
156             }
157         }
158         /* No 1000BASE-X, so assume 1000BASE-T/1000BASE-TX 10BASE-T register set */
159         /* Check for 1000BASE-T. */
160         btsr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_1000BTSR);
161         if (btsr < 0) {
162             HDF_LOGE("PHY 1000BT status");
163             return PHY_DUPLEX_HALF;
164         }
165 
166         if (btsr != 0xFFFF) {
167             if ((uint32_t)btsr & PHY_1000BTSR_1000FD) {
168                 return PHY_DUPLEX_FULL;
169             } else if ((uint32_t)btsr & PHY_1000BTSR_1000HD) {
170                 return PHY_DUPLEX_HALF;
171             }
172         }
173     }
174     /* Check Basic Management Control Register first. */
175     bmcr = HiethMdioRead(ld, phyAccess->phyAddr, PHY_BMCR);
176     if (bmcr < 0) {
177         HDF_LOGE("PHY duplex");
178         return PHY_DUPLEX_HALF;
179     }
180     /* Check if auto-negotiation is on. */
181     if ((uint32_t)bmcr & BMCR_AN_ENABLE) {
182         /* Get auto-negotiation results. */
183         anlpar = HiethMdioRead(ld, phyAccess->phyAddr, PHY_ANLPAR);
184         if (anlpar < 0) {
185             HDF_LOGE("PHY AN duplex");
186             return PHY_DUPLEX_HALF;
187         }
188         return ((uint32_t)anlpar & (ANLPAR_10FD | ANLPAR_TXFD)) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
189     }
190     /* Get speed from basic control settings. */
191     return ((uint32_t)bmcr & BMCR_FULL_DUPLEX) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
192 }
193