]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/network/drvPPCBMac/BMacEnetMII.cpp
4f981636853b185dd7e090b7afa6f1185b1d51e3
[apple/xnu.git] / iokit / Drivers / network / drvPPCBMac / BMacEnetMII.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1998-1999 by Apple Computer, Inc., All rights reserved.
24 *
25 * MII/PHY (National Semiconductor DP83840/DP83840A) support methods.
26 * It is general enough to work with most MII/PHYs.
27 *
28 * HISTORY
29 *
30 */
31
32 #include "BMacEnet.h"
33 #include "BMacEnetPrivate.h"
34
35 /*
36 * Read from MII/PHY registers.
37 */
38 bool BMacEnet::miiReadWord(unsigned short *dataPtr, unsigned short reg,
39 unsigned char phy)
40 {
41 int i;
42 miiFrameUnion frame;
43 unsigned short phyreg;
44 bool ret = true;
45
46 do
47 {
48 // Write preamble
49 //
50 miiWrite(MII_FRAME_PREAMBLE, MII_FRAME_SIZE);
51
52 if ( miiCheckZeroBit() == true )
53 {
54 // IOLog("Ethernet(BMac): MII not floating before read\n\r");
55 ret = false;
56 break;
57 }
58
59 // Prepare command frame
60 //
61 frame.data = MII_FRAME_READ;
62 frame.bit.regad = reg;
63 frame.bit.phyad = phy;
64
65 // write ST, OP, PHYAD, REGAD in the MII command frame
66 //
67 miiWrite(frame.data, 14);
68
69 // Hi-Z state
70 // Make sure the PHY generated a zero bit after the 2nd Hi-Z bit
71 //
72
73 miiOutThreeState();
74
75 if (miiCheckZeroBit() == false)
76 {
77 // IOLog("Ethernet(BMac): MII not driven after turnaround\n\r");
78 ret = false;
79 break;
80 }
81
82 // read 16-bit data
83 //
84 phyreg = 0;
85 for (i = 0; i < 16; i++)
86 {
87 phyreg = miiReadBit() | (phyreg << 1);
88 }
89 if (dataPtr)
90 *dataPtr = phyreg;
91
92 // Hi-Z state
93 miiOutThreeState();
94
95 if (miiCheckZeroBit() == true)
96 {
97 // IOLog("Ethernet(BMac): MII not floating after read\n\r");
98 ret = false;
99 break;
100 }
101 }
102 while ( 0 );
103
104 return ret;
105 }
106
107 /*
108 * Write to MII/PHY registers.
109 */
110 bool BMacEnet::miiWriteWord(unsigned short data, unsigned short reg,
111 unsigned char phy)
112 {
113 miiFrameUnion frame;
114 bool ret = true;
115
116 do
117 {
118 // Write preamble
119 //
120 miiWrite(MII_FRAME_PREAMBLE, MII_FRAME_SIZE);
121
122 if (miiCheckZeroBit() == true)
123 {
124 ret = false;
125 break;
126 }
127
128 // Prepare command frame
129 //
130 frame.data = MII_FRAME_WRITE;
131 frame.bit.regad = reg;
132 frame.bit.phyad = phy;
133 frame.bit.data = data;
134
135 // Write command frame
136 //
137 miiWrite(frame.data, MII_FRAME_SIZE);
138
139 // Hi-Z state
140 miiOutThreeState();
141
142 if (miiCheckZeroBit() == true)
143 {
144 ret = false;
145 break;
146 }
147 }
148 while ( 0 );
149
150 return ret;
151 }
152
153 /*
154 * Write 'dataSize' number of bits to the MII management interface,
155 * starting with the most significant bit of 'miiData'.
156 *
157 */
158 void BMacEnet::miiWrite(unsigned int miiData, unsigned int dataSize)
159 {
160 int i;
161 u_int16_t regValue;
162
163 regValue = kMIFCSR_DataOutEnable;
164
165 for (i = dataSize; i > 0; i--)
166 {
167 int bit = ((miiData & 0x80000000) ? kMIFCSR_DataOut : 0);
168
169 regValue &= ~(kMIFCSR_Clock | kMIFCSR_DataOut) ;
170 regValue |= bit;
171 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue);
172 IODelay(phyMIIDelay);
173
174 regValue |= kMIFCSR_Clock;
175 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue );
176 IODelay(phyMIIDelay);
177
178 miiData = miiData << 1;
179 }
180 }
181
182 /*
183 * Read one bit from the MII management interface.
184 */
185 int BMacEnet::miiReadBit()
186 {
187 u_int16_t regValue;
188 u_int16_t regValueRead;
189
190 regValue = 0;
191
192 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue);
193 IODelay(phyMIIDelay);
194
195 regValue |= kMIFCSR_Clock;
196 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue);
197 IODelay(phyMIIDelay);
198
199 regValueRead = ReadBigMacRegister(ioBaseEnet, kMIFCSR);
200 IODelay(phyMIIDelay); // delay next invocation of this routine
201
202 return ( (regValueRead & kMIFCSR_DataIn) ? 1 : 0 );
203 }
204
205 /*
206 * Read the zero bit on the second clock of the turn-around (TA)
207 * when reading a PHY register.
208 */
209 bool BMacEnet::miiCheckZeroBit()
210 {
211 u_int16_t regValue;
212
213 regValue = ReadBigMacRegister(ioBaseEnet, kMIFCSR);
214
215 return (((regValue & kMIFCSR_DataIn) == 0) ? true : false );
216 }
217
218 /*
219 * Tri-state the STA's MDIO pin.
220 */
221 void BMacEnet::miiOutThreeState()
222 {
223 u_int16_t regValue;
224
225 regValue = 0;
226 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue);
227 IODelay(phyMIIDelay);
228
229 regValue |= kMIFCSR_Clock;
230 WriteBigMacRegister(ioBaseEnet, kMIFCSR, regValue);
231 IODelay(phyMIIDelay);
232 }
233
234 bool BMacEnet::miiResetPHY(unsigned char phy)
235 {
236 int i = MII_RESET_TIMEOUT;
237 unsigned short mii_control;
238
239 // Set the reset bit
240 //
241 miiWriteWord(MII_CONTROL_RESET, MII_CONTROL, phy);
242
243 IOSleep(MII_RESET_DELAY);
244
245 // Wait till reset process is complete (MII_CONTROL_RESET returns to zero)
246 //
247 while (i > 0)
248 {
249 if (miiReadWord(&mii_control, MII_CONTROL, phy) == false)
250 return false;
251
252 if (!(mii_control & MII_CONTROL_RESET))
253 {
254 miiReadWord(&mii_control, MII_CONTROL, phy);
255 mii_control &= ~MII_CONTROL_ISOLATE;
256 miiWriteWord(mii_control, MII_CONTROL, phy);
257 return true;
258 }
259
260 IOSleep(MII_RESET_DELAY);
261 i -= MII_RESET_DELAY;
262 }
263 return false;
264 }
265
266 bool BMacEnet::miiWaitForLink(unsigned char phy)
267 {
268 int i = MII_LINK_TIMEOUT;
269 unsigned short mii_status;
270
271 while (i > 0)
272 {
273 if (miiReadWord(&mii_status, MII_STATUS, phy) == false)
274 return false;
275
276 if (mii_status & MII_STATUS_LINK_STATUS)
277 return true;
278
279 IOSleep(MII_LINK_DELAY);
280 i -= MII_LINK_DELAY;
281 }
282 return false;
283 }
284
285 bool BMacEnet::miiWaitForAutoNegotiation(unsigned char phy)
286 {
287 int i = MII_LINK_TIMEOUT;
288 unsigned short mii_status;
289
290 while (i > 0)
291 {
292 if (miiReadWord(&mii_status, MII_STATUS, phy) == false)
293 return false;
294
295 if (mii_status & MII_STATUS_NEGOTIATION_COMPLETE)
296 return true;
297
298 IOSleep(MII_LINK_DELAY);
299 i -= MII_LINK_DELAY;
300 }
301 return false;
302 }
303
304 void BMacEnet::miiRestartAutoNegotiation(unsigned char phy)
305 {
306 unsigned short mii_control;
307
308 miiReadWord(&mii_control, MII_CONTROL, phy);
309 mii_control |= MII_CONTROL_RESTART_NEGOTIATION;
310 miiWriteWord(mii_control, MII_CONTROL, phy);
311
312 /*
313 * If the system is not connected to the network, then auto-negotiation
314 * never completes and we hang in this loop!
315 */
316 #if 0
317 while (1)
318 {
319 miiReadWord(&mii_control, MII_CONTROL, phy);
320 if ((mii_control & MII_CONTROL_RESTART_NEGOTIATION) == 0)
321 break;
322 }
323 #endif
324 }
325
326 /*
327 * Find the first PHY device on the MII interface.
328 *
329 * Return
330 * true PHY found
331 * false PHY not found
332 */
333 bool BMacEnet::miiFindPHY(unsigned char *phy)
334 {
335 int i;
336
337 *phy = 0xff;
338
339 // The first two PHY registers are required.
340 //
341 for (i = 0; i < MII_MAX_PHY; i++)
342 {
343 if (miiReadWord(NULL, MII_STATUS, i) &&
344 miiReadWord(NULL, MII_CONTROL, i))
345 break;
346 }
347
348 if (i >= MII_MAX_PHY)
349 return false;
350
351 *phy = i;
352
353 return true;
354 }
355
356 /*
357 *
358 *
359 */
360 bool BMacEnet::miiInitializePHY(unsigned char phy)
361 {
362 u_int16_t phyWord;
363
364 // Clear then set the enable auto-negotiation bit
365 //
366 miiReadWord(&phyWord, MII_CONTROL, phy);
367 phyWord &= ~MII_CONTROL_AUTONEGOTIATION;
368 miiWriteWord(phyWord, MII_CONTROL, phy);
369
370 // Advertise 10/100 Half/Full duplex capable to link partner
371 //
372 miiReadWord(&phyWord, MII_ADVERTISEMENT, phy);
373 phyWord |= (MII_ANAR_100BASETX_FD | MII_ANAR_100BASETX |
374 MII_ANAR_10BASET_FD | MII_ANAR_10BASET );
375 miiWriteWord(phyWord, MII_ADVERTISEMENT, phy);
376
377 // Set enable auto-negotiation bit
378 //
379 miiReadWord(&phyWord, MII_CONTROL, phy);
380 phyWord |= MII_CONTROL_AUTONEGOTIATION;
381 miiWriteWord(phyWord, MII_CONTROL, phy);
382
383 miiRestartAutoNegotiation(phy);
384
385 return true;
386 }