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