2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1996 NeXT Software, Inc. All rights reserved.
30 #include "i82557PHY.h"
32 //---------------------------------------------------------------------------
33 // Function: _logMDIStatus
36 // Dump the contents of the MDI status register.
39 _logMDIStatus(mdi_reg_t reg
)
41 if (reg
& MDI_STATUS_T4
)
42 IOLog("PHY: T4 capable\n");
43 if (reg
& MDI_STATUS_TX_FD
)
44 IOLog("PHY: 100Base-TX full duplex capable\n");
45 if (reg
& MDI_STATUS_TX_HD
)
46 IOLog("PHY: 100Base-TX half duplex capable\n");
47 if (reg
& MDI_STATUS_10_FD
)
48 IOLog("PHY: 10Base-T full duplex capable\n");
49 if (reg
& MDI_STATUS_10_HD
)
50 IOLog("PHY: 10Base-T half duplex capable\n");
51 if (reg
& MDI_STATUS_EXTENDED_CAPABILITY
)
52 IOLog("PHY: has extended capability registers\n");
53 if (reg
& MDI_STATUS_JABBER_DETECTED
)
54 IOLog("PHY: jabberDetect set\n");
55 if (reg
& MDI_STATUS_AUTONEG_CAPABLE
)
56 IOLog("PHY: auto negotiation capable\n");
57 IOLog("PHY: link is %s\n", (reg
& MDI_STATUS_LINK_STATUS
) ? "UP" : "DOWN");
61 //---------------------------------------------------------------------------
62 // Function: _getModelId
65 // Read the MDI ID registers and form a single 32-bit id.
67 UInt32
Intel82557::_phyGetID()
70 _mdiReadPHY(phyAddr
, MDI_REG_PHYID_WORD_1
, &id1
);
71 _mdiReadPHY(phyAddr
, MDI_REG_PHYID_WORD_2
, &id2
);
72 return ((id2
<< 16) | id1
);
75 //---------------------------------------------------------------------------
76 // Function: _phySetMedium
79 // Setup the PHY to the medium type given.
80 // Returns true on success.
82 bool Intel82557::_phySetMedium(mediumType_t medium
)
86 mediumType_t phyMedium
= medium
;
87 UInt32 mediumCapableMask
;
89 // Reset PHY before changing medium selection.
93 // Get local capability.
95 _mdiReadPHY(phyAddr
, MDI_REG_STATUS
, &status
);
97 // Create a medium capable mask.
99 mediumCapableMask
= (status
>> 11) & 0x1f;
101 // Force the PHY's data rate and duplex settings if the medium type
102 // chosen is not AUTO.
104 if (phyMedium
!= MEDIUM_TYPE_AUTO
) {
105 if ((MEDIUM_TYPE_TO_MASK(phyMedium
) & mediumCapableMask
) == 0) {
106 // Hardware is not capable of selecting the user-selected
112 // Medium chosen is valid, go ahead and set PHY.
114 bool speed100
= false;
115 bool fullDuplex
= false;
117 if ((medium
== MEDIUM_TYPE_TX_HD
) ||
118 (medium
== MEDIUM_TYPE_TX_FD
) ||
119 (medium
== MEDIUM_TYPE_T4
))
122 if ((medium
== MEDIUM_TYPE_10_FD
) || (medium
== MEDIUM_TYPE_TX_FD
))
125 // Disable auto-negotiation function and force speed + duplex.
129 control
= ((speed100
? MDI_CONTROL_100
: 0) |
130 (fullDuplex
? MDI_CONTROL_FULL_DUPLEX
: 0));
132 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
134 VPRINT("%s: user forced %s Mbit/s%s mode\n", getName(),
135 speed100
? "100" : "10",
136 fullDuplex
? " full duplex" : "");
142 // For MEDIUM_TYPE_AUTO, enable and restart auto-negotiation.
144 control
= MDI_CONTROL_AUTONEG_ENABLE
;
145 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
147 control
|= MDI_CONTROL_RESTART_AUTONEG
;
148 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
151 // Some special bit twiddling for NSC83840.
153 if (phyID
== PHY_MODEL_NSC83840
) {
154 /* set-up National Semiconductor 83840 specific registers */
158 VPRINT("%s: setting NSC83840-specific registers\n", getName());
159 _mdiReadPHY(phyAddr
, NSC83840_REG_PCR
, ®
);
162 * This bit MUST be set, otherwise the card may not transmit at
163 * all in 100Mb/s mode. This is specially true for 82557 cards
164 * with the DP83840 PHY.
166 * In the NSC documentation, bit 10 of PCS register is labeled
167 * as a reserved bit. What is the real function of this bit?
169 reg
|= (NSC83840_PCR_TXREADY
| NSC83840_PCR_CIM_DIS
);
171 _mdiWritePHY(phyAddr
, NSC83840_REG_PCR
, reg
);
174 currentMediumType
= medium
;
179 //---------------------------------------------------------------------------
180 // Function: _phyAddMediumType
183 // Add a single medium object to the medium dictionary.
184 // Also add the medium object to an array for fast lookup.
186 bool Intel82557::_phyAddMediumType(UInt32 type
, UInt32 speed
, UInt32 code
)
188 IONetworkMedium
* medium
;
191 medium
= IONetworkMedium::medium(type
, speed
, 0, code
);
193 ret
= IONetworkMedium::addMedium(mediumDict
, medium
);
195 mediumTable
[code
] = medium
;
201 //---------------------------------------------------------------------------
202 // Function: _phyPublishMedia
205 // Examine the PHY capabilities and advertise all supported medium types.
207 // FIXME: Non PHY medium types are not probed.
211 void Intel82557::_phyPublishMedia()
215 // Read the PHY's media capability.
217 _mdiReadPHY(phyAddr
, MDI_REG_STATUS
, &status
);
219 _phyAddMediumType(kIOMediumEthernetAuto
,
223 if (status
& MDI_STATUS_10_HD
)
224 _phyAddMediumType(kIOMediumEthernet10BaseT
| kIOMediumOptionHalfDuplex
,
228 if (status
& MDI_STATUS_10_FD
)
229 _phyAddMediumType(kIOMediumEthernet10BaseT
| kIOMediumOptionFullDuplex
,
233 if (status
& MDI_STATUS_TX_HD
)
235 kIOMediumEthernet100BaseTX
| kIOMediumOptionHalfDuplex
,
239 if (status
& MDI_STATUS_TX_FD
)
241 kIOMediumEthernet100BaseTX
| kIOMediumOptionFullDuplex
,
245 if (status
& MDI_STATUS_T4
)
246 _phyAddMediumType(kIOMediumEthernet100BaseT4
,
251 //---------------------------------------------------------------------------
252 // Function: _phyReset
257 #define PHY_RESET_TIMEOUT 100 // ms
258 #define PHY_RESET_DELAY 10 // ms
259 #define PHY_POST_RESET_DELAY 300 // us
261 bool Intel82557::_phyReset()
263 int i
= PHY_RESET_TIMEOUT
;
266 if (!_mdiReadPHY(phyAddr
, MDI_REG_CONTROL
, &control
))
269 // Set the reset bit in the PHY Control register
271 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
| MDI_CONTROL_RESET
);
273 // Wait till reset process is complete (MDI_CONTROL_RESET returns to zero)
276 if (!_mdiReadPHY(phyAddr
, MDI_REG_CONTROL
, &control
))
278 if ((control
& MDI_CONTROL_RESET
) == 0) {
279 IODelay(PHY_POST_RESET_DELAY
);
282 IOSleep(PHY_RESET_DELAY
);
283 i
-= PHY_RESET_DELAY
;
288 //---------------------------------------------------------------------------
289 // Function: _phyWaitAutoNegotiation
292 // Wait until auto-negotiation is complete.
294 #define PHY_NWAY_TIMEOUT 5000 // ms
295 #define PHY_NWAY_DELAY 20 // ms
297 bool Intel82557::_phyWaitAutoNegotiation()
299 int i
= PHY_NWAY_TIMEOUT
;
303 if (!_mdiReadPHY(phyAddr
, MDI_REG_STATUS
, &status
))
306 if (status
& MDI_STATUS_AUTONEG_COMPLETE
)
309 IOSleep(PHY_NWAY_DELAY
);
315 //---------------------------------------------------------------------------
316 // Function: _phyProbe
319 // Find out which PHY is active.
321 #define AUTONEGOTIATE_TIMEOUT 35
323 bool Intel82557::_phyProbe()
325 bool foundPhy1
= false;
329 if (phyAddr
== PHY_ADDRESS_I82503
) {
330 VPRINT("%s: overriding to use Intel 82503", getName());
334 if (phyAddr
> 0 && phyAddr
< PHY_ADDRESS_MAX
) {
335 VPRINT("%s: looking for Phy 1 at address %d\n", getName(), phyAddr
);
336 _mdiReadPHY(phyAddr
, MDI_REG_CONTROL
, &control
);
337 _mdiReadPHY(phyAddr
, MDI_REG_STATUS
, &status
); // do it twice
338 _mdiReadPHY(phyAddr
, MDI_REG_STATUS
, &status
);
339 if (control
== 0xffff || (status
== 0 && control
== 0))
341 VPRINT("%s: Phy 1 at address %d does not exist\n", getName(),
345 VPRINT("%s: Phy 1 at address %d exists\n", getName(), phyAddr
);
347 if (status
& MDI_STATUS_LINK_STATUS
) {
348 VPRINT("%s: found Phy 1 at address %d with link\n",
350 return true; // use PHY1
355 // PHY1 does not exist, or it does not have valid link.
356 // Try PHY0 at address 0.
358 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_CONTROL
, &control
);
359 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_STATUS
, &status
);
361 if (control
== 0xffff || (status
== 0 && control
== 0)) {
362 if (phyAddr
== 0) { /* if address forced to 0, then fail */
363 IOLog("%s: phy0 not detected\n", getName());
366 if (foundPhy1
== true) {
367 VPRINT("%s: no Phy at address 0, using Phy 1 without link\n",
369 return true; // use PHY1 without a valid link
371 VPRINT("%s: no Phy at address 0, defaulting to 82503\n", getName());
372 phyAddr
= PHY_ADDRESS_I82503
;
376 // must isolate PHY1 electrically before using PHY0.
378 if (foundPhy1
== true) {
379 control
= MDI_CONTROL_ISOLATE
;
380 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
384 // Enable and restart auto-negotiation on PHY0.
386 VPRINT("%s: starting auto-negotiation on Phy 0", getName());
387 control
= MDI_CONTROL_AUTONEG_ENABLE
;
388 _mdiWritePHY(PHY_ADDRESS_0
, MDI_REG_CONTROL
, control
);
390 control
|= MDI_CONTROL_RESTART_AUTONEG
;
391 _mdiWritePHY(PHY_ADDRESS_0
, MDI_REG_CONTROL
, control
);
393 for (int i
= 0; i
< AUTONEGOTIATE_TIMEOUT
; i
++) {
394 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_STATUS
, &status
);
395 if (status
& MDI_STATUS_AUTONEG_COMPLETE
)
399 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_STATUS
, &status
);
400 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_STATUS
, &status
);
401 _mdiReadPHY(PHY_ADDRESS_0
, MDI_REG_STATUS
, &status
);
402 if ((status
& MDI_STATUS_LINK_STATUS
) || foundPhy1
== false) {
403 VPRINT("%s: using Phy 0 at address 0\n", getName());
410 VPRINT("%s: using Phy 1 without link\n", getName());
411 control
= MDI_CONTROL_ISOLATE
;
412 _mdiWritePHY(PHY_ADDRESS_0
, MDI_REG_CONTROL
, control
);
415 // Enable and restart auto-negotiation on PHY1.
417 control
= MDI_CONTROL_AUTONEG_ENABLE
;
418 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
420 control
|= MDI_CONTROL_RESTART_AUTONEG
;
421 _mdiWritePHY(phyAddr
, MDI_REG_CONTROL
, control
);
424 VPRINT("%s: PHY model id is 0x%08lx\n", getName(), phyID
);
425 phyID
&= PHY_MODEL_MASK
;
430 //---------------------------------------------------------------------------
431 // Function: _phyGetMediumTypeFromBits
434 // Return the medium type that correspond to the given specifiers.
436 mediumType_t
Intel82557::_phyGetMediumTypeFromBits(bool rate100
,
440 mediumType_t mediumType
;
443 mediumType
= MEDIUM_TYPE_T4
;
447 mediumType
= MEDIUM_TYPE_TX_FD
;
449 mediumType
= MEDIUM_TYPE_TX_HD
;
453 mediumType
= MEDIUM_TYPE_10_FD
;
455 mediumType
= MEDIUM_TYPE_10_HD
;
461 //---------------------------------------------------------------------------
462 // Function: _phyGetMediumWithCode
465 // Returns the IONetworkMedium object associated with the given type.
467 IONetworkMedium
* Intel82557::_phyGetMediumWithType(UInt32 type
)
469 if (type
< MEDIUM_TYPE_INVALID
)
470 return mediumTable
[type
];
475 //---------------------------------------------------------------------------
476 // Function: _phyReportLinkStatus
479 // Called periodically to monitor for link changes. When a change
480 // is detected, determine the current link and report it to the
481 // upper layers by calling IONetworkController::setLinkStatus().
483 void Intel82557::_phyReportLinkStatus( bool firstPoll
= false )
486 UInt16 phyStatusChange
;
488 // Read PHY status register.
490 _mdiReadPHY( phyAddr
, MDI_REG_STATUS
, &phyStatus
);
492 // Detect a change in the two link related bits.
493 // Remember that the link status bit will latch a link fail
494 // condition (should not miss a link down event).
496 phyStatusChange
= ( phyStatusPrev
^ phyStatus
) &
497 ( MDI_STATUS_LINK_STATUS
|
498 MDI_STATUS_AUTONEG_COMPLETE
);
500 if ( phyStatusChange
|| firstPoll
)
504 // For the initial link status poll, wait a bit, then
505 // re-read the status register to clear any latched bits.
507 _phyWaitAutoNegotiation();
508 _mdiReadPHY( phyAddr
, MDI_REG_STATUS
, &phyStatus
);
509 _mdiReadPHY( phyAddr
, MDI_REG_STATUS
, &phyStatus
);
512 // IOLog("PhyStatus: %04x\n", phyStatus);
514 // Determine the link status.
516 if ( ( phyStatus
& MDI_STATUS_LINK_STATUS
) &&
517 ( phyStatus
& MDI_STATUS_AUTONEG_COMPLETE
) )
519 // Excellent, link is up.
521 IONetworkMedium
* activeMedium
;
523 activeMedium
= _phyGetMediumWithType( _phyGetActiveMedium() );
525 setLinkStatus( kIONetworkLinkValid
| kIONetworkLinkActive
,
528 // IOLog("link is up %lx\n",
529 // activeMedium ? activeMedium->getType() : 0);
535 setLinkStatus( kIONetworkLinkValid
, 0 );
537 // IOLog("link is down\n");
540 // Save phyStatus for the next run.
542 phyStatusPrev
= phyStatus
;
546 //---------------------------------------------------------------------------
547 // Function: _phyGetActiveMedium
550 // Once the PHY reports that the link is up, this method can be called
551 // to return the type of link that was established.
553 mediumType_t
Intel82557::_phyGetActiveMedium()
559 // For the simple case where the media selection is not
560 // automatic (e.g. forced to 100BaseTX).
562 if ( currentMediumType
!= MEDIUM_TYPE_AUTO
)
564 medium
= currentMediumType
;
568 // i82553 has a special register for determining the speed and
569 // duplex mode settings.
571 if ( ( phyID
== PHY_MODEL_I82553_A_B
) ||
572 ( phyID
== PHY_MODEL_I82553_C
) )
574 _mdiReadPHY( phyAddr
, I82553_REG_SCR
, ®
);
576 medium
= _phyGetMediumTypeFromBits( reg
& I82553_SCR_100
,
577 reg
& I82553_SCR_FULL_DUPLEX
,
578 reg
& I82553_SCR_T4
);
581 else if ( phyID
== PHY_MODEL_NSC83840
)
583 // For NSC83840, we use the 83840 specific register to determine
584 // the link speed and duplex mode setting. Early 83840 devices
585 // did not seem to report the remote capabilities when the link
586 // partner does not support NWay.
590 _mdiReadPHY( phyAddr
, MDI_REG_ANEX
, &exp
);
592 if ( ( exp
& MDI_ANEX_LP_AUTONEGOTIABLE
) == 0 )
594 _mdiReadPHY( phyAddr
, NSC83840_REG_PAR
, ®
);
596 medium
= _phyGetMediumTypeFromBits(
597 !(reg
& NSC83840_PAR_SPEED_10
),
598 (reg
& NSC83840_PAR_DUPLEX_STAT
),
604 // For generic PHY, use the standard PHY registers.
606 // Use the local and remote capability words to determine the
607 // current active medium.
612 _mdiReadPHY( phyAddr
, MDI_REG_ANLP
, &lpa
);
613 _mdiReadPHY( phyAddr
, MDI_REG_ANAR
, &mya
);
615 mya
&= lpa
; // obtain common capabilities mask.
617 // Observe PHY medium precedence.
619 if ( mya
& MDI_ANAR_TX_FD
) medium
= MEDIUM_TYPE_TX_FD
;
620 else if ( mya
& MDI_ANAR_T4
) medium
= MEDIUM_TYPE_T4
;
621 else if ( mya
& MDI_ANAR_TX_HD
) medium
= MEDIUM_TYPE_TX_HD
;
622 else if ( mya
& MDI_ANAR_10_FD
) medium
= MEDIUM_TYPE_10_FD
;
623 else medium
= MEDIUM_TYPE_10_HD
;