]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 2001 | |
3 | * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | /* | |
25 | * This provides a bit-banged interface to the ethernet MII management | |
26 | * channel. | |
27 | */ | |
28 | ||
29 | #include <common.h> | |
30 | #include <miiphy.h> | |
31 | ||
32 | #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) | |
33 | ||
34 | /***************************************************************************** | |
35 | * | |
36 | * Read the OUI, manufacture's model number, and revision number. | |
37 | * | |
38 | * OUI: 22 bits (unsigned int) | |
39 | * Model: 6 bits (unsigned char) | |
40 | * Revision: 4 bits (unsigned char) | |
41 | * | |
42 | * Returns: | |
43 | * 0 on success | |
44 | */ | |
45 | int miiphy_info (unsigned char addr, | |
46 | unsigned int *oui, | |
47 | unsigned char *model, unsigned char *rev) | |
48 | { | |
49 | unsigned int reg = 0; | |
8bf3b005 | 50 | unsigned short tmp; |
c609719b | 51 | |
8bf3b005 | 52 | if (miiphy_read (addr, PHY_PHYIDR2, &tmp) != 0) { |
c609719b | 53 | #ifdef DEBUG |
4b9206ed | 54 | puts ("PHY ID register 2 read failed\n"); |
c609719b WD |
55 | #endif |
56 | return (-1); | |
57 | } | |
8bf3b005 | 58 | reg = tmp; |
c609719b WD |
59 | |
60 | #ifdef DEBUG | |
61 | printf ("PHY_PHYIDR2 @ 0x%x = 0x%04x\n", addr, reg); | |
62 | #endif | |
63 | if (reg == 0xFFFF) { | |
64 | /* No physical device present at this address */ | |
65 | return (-1); | |
66 | } | |
67 | ||
8bf3b005 | 68 | if (miiphy_read (addr, PHY_PHYIDR1, &tmp) != 0) { |
c609719b | 69 | #ifdef DEBUG |
4b9206ed | 70 | puts ("PHY ID register 1 read failed\n"); |
c609719b WD |
71 | #endif |
72 | return (-1); | |
73 | } | |
8bf3b005 | 74 | reg |= tmp << 16; |
c609719b WD |
75 | #ifdef DEBUG |
76 | printf ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); | |
77 | #endif | |
78 | *oui = ( reg >> 10); | |
79 | *model = (unsigned char) ((reg >> 4) & 0x0000003F); | |
80 | *rev = (unsigned char) ( reg & 0x0000000F); | |
81 | return (0); | |
82 | } | |
83 | ||
84 | ||
85 | /***************************************************************************** | |
86 | * | |
87 | * Reset the PHY. | |
88 | * Returns: | |
89 | * 0 on success | |
90 | */ | |
91 | int miiphy_reset (unsigned char addr) | |
92 | { | |
93 | unsigned short reg; | |
94 | int loop_cnt; | |
95 | ||
f89920c3 WD |
96 | if (miiphy_read (addr, PHY_BMCR, ®) != 0) { |
97 | #ifdef DEBUG | |
98 | printf ("PHY status read failed\n"); | |
99 | #endif | |
100 | return (-1); | |
101 | } | |
102 | if (miiphy_write (addr, PHY_BMCR, reg | 0x8000) != 0) { | |
c609719b | 103 | #ifdef DEBUG |
4b9206ed | 104 | puts ("PHY reset failed\n"); |
c609719b WD |
105 | #endif |
106 | return (-1); | |
107 | } | |
5653fc33 WD |
108 | #ifdef CONFIG_PHY_RESET_DELAY |
109 | udelay (CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ | |
110 | #endif | |
c609719b WD |
111 | /* |
112 | * Poll the control register for the reset bit to go to 0 (it is | |
113 | * auto-clearing). This should happen within 0.5 seconds per the | |
114 | * IEEE spec. | |
115 | */ | |
116 | loop_cnt = 0; | |
117 | reg = 0x8000; | |
118 | while (((reg & 0x8000) != 0) && (loop_cnt++ < 1000000)) { | |
119 | if (miiphy_read (addr, PHY_BMCR, ®) != 0) { | |
120 | # ifdef DEBUG | |
4b9206ed | 121 | puts ("PHY status read failed\n"); |
c609719b WD |
122 | # endif |
123 | return (-1); | |
124 | } | |
125 | } | |
126 | if ((reg & 0x8000) == 0) { | |
127 | return (0); | |
128 | } else { | |
4b9206ed | 129 | puts ("PHY reset timed out\n"); |
c609719b WD |
130 | return (-1); |
131 | } | |
132 | return (0); | |
133 | } | |
134 | ||
135 | ||
136 | /***************************************************************************** | |
137 | * | |
138 | * Determine the ethernet speed (10/100). | |
139 | */ | |
140 | int miiphy_speed (unsigned char addr) | |
141 | { | |
142 | unsigned short reg; | |
143 | ||
6fb6af6d | 144 | #if defined(CONFIG_PHY_GIGE) |
855a496f WD |
145 | if (miiphy_read (addr, PHY_1000BTSR, ®)) { |
146 | printf ("PHY 1000BT Status read failed\n"); | |
147 | } else { | |
148 | if (reg != 0xFFFF) { | |
149 | if ((reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) !=0) { | |
150 | return (_1000BASET); | |
151 | } | |
152 | } | |
153 | } | |
6fb6af6d | 154 | #endif /* CONFIG_PHY_GIGE */ |
855a496f | 155 | |
a56bd922 WD |
156 | /* Check Basic Management Control Register first. */ |
157 | if (miiphy_read (addr, PHY_BMCR, ®)) { | |
158 | puts ("PHY speed read failed, assuming 10bT\n"); | |
c609719b WD |
159 | return (_10BASET); |
160 | } | |
a56bd922 WD |
161 | /* Check if auto-negotiation is on. */ |
162 | if ((reg & PHY_BMCR_AUTON) != 0) { | |
163 | /* Get auto-negotiation results. */ | |
164 | if (miiphy_read (addr, PHY_ANLPAR, ®)) { | |
165 | puts ("PHY AN speed read failed, assuming 10bT\n"); | |
166 | return (_10BASET); | |
167 | } | |
168 | if ((reg & PHY_ANLPAR_100) != 0) { | |
169 | return (_100BASET); | |
170 | } else { | |
171 | return (_10BASET); | |
172 | } | |
173 | } | |
174 | /* Get speed from basic control settings. */ | |
175 | else if (reg & PHY_BMCR_100MB) { | |
c609719b WD |
176 | return (_100BASET); |
177 | } else { | |
178 | return (_10BASET); | |
179 | } | |
a56bd922 | 180 | |
c609719b WD |
181 | } |
182 | ||
183 | ||
184 | /***************************************************************************** | |
185 | * | |
186 | * Determine full/half duplex. | |
187 | */ | |
188 | int miiphy_duplex (unsigned char addr) | |
189 | { | |
190 | unsigned short reg; | |
191 | ||
6fb6af6d | 192 | #if defined(CONFIG_PHY_GIGE) |
855a496f WD |
193 | if (miiphy_read (addr, PHY_1000BTSR, ®)) { |
194 | printf ("PHY 1000BT Status read failed\n"); | |
195 | } else { | |
196 | if ( (reg != 0xFFFF) && | |
197 | (reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) ) { | |
198 | if ((reg & PHY_1000BTSR_1000FD) !=0) { | |
199 | return (FULL); | |
200 | } else { | |
201 | return (HALF); | |
202 | } | |
203 | } | |
204 | } | |
6fb6af6d | 205 | #endif /* CONFIG_PHY_GIGE */ |
855a496f | 206 | |
a56bd922 WD |
207 | /* Check Basic Management Control Register first. */ |
208 | if (miiphy_read (addr, PHY_BMCR, ®)) { | |
4b9206ed | 209 | puts ("PHY duplex read failed, assuming half duplex\n"); |
c609719b WD |
210 | return (HALF); |
211 | } | |
a56bd922 WD |
212 | /* Check if auto-negotiation is on. */ |
213 | if ((reg & PHY_BMCR_AUTON) != 0) { | |
214 | /* Get auto-negotiation results. */ | |
215 | if (miiphy_read (addr, PHY_ANLPAR, ®)) { | |
216 | puts ("PHY AN duplex read failed, assuming half duplex\n"); | |
217 | return (HALF); | |
218 | } | |
c609719b | 219 | |
a56bd922 WD |
220 | if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) { |
221 | return (FULL); | |
222 | } else { | |
223 | return (HALF); | |
224 | } | |
225 | } | |
226 | /* Get speed from basic control settings. */ | |
227 | else if (reg & PHY_BMCR_DPLX) { | |
c609719b WD |
228 | return (FULL); |
229 | } else { | |
230 | return (HALF); | |
231 | } | |
a56bd922 | 232 | |
c609719b WD |
233 | } |
234 | ||
fc3e2165 WD |
235 | #ifdef CFG_FAULT_ECHO_LINK_DOWN |
236 | /***************************************************************************** | |
237 | * | |
238 | * Determine link status | |
239 | */ | |
240 | int miiphy_link (unsigned char addr) | |
241 | { | |
242 | unsigned short reg; | |
243 | ||
a3d991bd WD |
244 | /* dummy read; needed to latch some phys */ |
245 | (void)miiphy_read(addr, PHY_BMSR, ®); | |
fc3e2165 | 246 | if (miiphy_read (addr, PHY_BMSR, ®)) { |
4b9206ed | 247 | puts ("PHY_BMSR read failed, assuming no link\n"); |
fc3e2165 WD |
248 | return (0); |
249 | } | |
250 | ||
251 | /* Determine if a link is active */ | |
252 | if ((reg & PHY_BMSR_LS) != 0) { | |
253 | return (1); | |
254 | } else { | |
255 | return (0); | |
256 | } | |
257 | } | |
258 | #endif | |
259 | ||
c609719b | 260 | #endif /* CONFIG_MII || (CONFIG_COMMANDS & CFG_CMD_MII) */ |