3 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License"). You may not use this file except in compliance with the
10 * License. Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
13 * This Original Code and all software distributed under the License are
14 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
21 * @APPLE_LICENSE_HEADER_END@
25 #include "UniNEnetPrivate.h"
27 #define super IOEthernetController
29 // Set EXTRANEOUS_PM_DELAYS to 1 to enable absurdly long delays.
31 #define EXTRANEOUS_PM_DELAYS 0
33 // --------------------------------------------------------------------------
34 // Method: registerWithPolicyMaker
37 // initialize the driver for power managment and register ourselves with
40 UniNEnet::registerWithPolicyMaker(IOService
* policyMaker
)
44 From iokit/IOKit/pwr_mgt/IOPMpowerState.h
47 unsigned long version; // version number of this struct
48 IOPMPowerFlags capabilityFlags; // bits that describe the capability
49 IOPMPowerFlags outputPowerCharacter; // description (to power domain children)
50 IOPMPowerFlags inputPowerRequirement; // description (to power domain parent)
51 unsigned long staticPower; // average consumption in milliwatts
52 unsigned long unbudgetedPower; // additional consumption from separate power supply (mw)
53 unsigned long powerToAttain; // additional power to attain this state from next lower state (in mw)
54 unsigned long timeToAttain; // (in microseconds)
55 unsigned long settleUpTime; // (microseconds)
56 unsigned long timeToLower; // (in microseconds)
57 unsigned long settleDownTime; // (microseconds)
58 unsigned long powerDomainBudget; // power in mw a domain in this state can deliver to its children
63 #define num_of_power_states 2
65 static IOPMPowerState ourPowerStates
[num_of_power_states
] = {
66 {1, 0,0,0,0,0,0,0,0,0,0,0},
67 {1,IOPMDeviceUsable
| IOPMMaxPerformance
, IOPMPowerOn
, IOPMPowerOn
, 50,0,0,
68 kUniNsettle_time
, kUniNsettle_time
, kUniNsettle_time
, kUniNsettle_time
,0}
69 // 50 milliwatts above is just a guess right now, since the ethernet is part of Uni-N
72 currentPowerState
= kMaxUniNEnetPowerState
;
73 return policyMaker
->registerPowerDriver(this, ourPowerStates
, num_of_power_states
);
76 // Method: maxCapabilityForDomainState
79 // returns the maximun state of card power, which would be
80 // power on without any attempt to power manager.
82 UniNEnet::maxCapabilityForDomainState(IOPMPowerFlags domainState
)
84 if( domainState
& IOPMPowerOn
)
85 return kMaxUniNEnetPowerState
; //In reality, it's just array element 1 for Uni-N
90 // Method: initialPowerStateForDomainState
93 // The power domain may be changing state. If power is on in the new
94 // state, that will not affect our state at all. If domain power is off,
95 // we can attain only our lowest state, which is off.
98 UniNEnet::initialPowerStateForDomainState( IOPMPowerFlags domainState
)
100 if( domainState
& IOPMPowerOn
)
101 return currentPowerState
;
107 // Method: powerStateForDomainState
110 // The power domain may be changing state. If power is on in the new
111 // state, that will not affect our state at all. If domain power is off,
112 // we can attain only our lowest state, which is off.
114 UniNEnet::powerStateForDomainState(IOPMPowerFlags domainState
)
116 if( domainState
& IOPMPowerOn
)
117 return currentPowerState
;
122 // Method: setPowerState
124 IOReturn
UniNEnet::setPowerState(unsigned long powerStateOrdinal
,
125 IOService
* whatDevice
)
127 volatile UInt32 clockReg
;
129 // Do not do anything if the state is invalid.
130 if (powerStateOrdinal
>= num_of_power_states
)
131 return IOPMNoSuchState
;
133 if (powerStateOrdinal
== currentPowerState
)
134 return IOPMAckImplied
; //no change required
136 // otherwise remember the new state:
137 currentPowerState
= powerStateOrdinal
;
139 IOLog("UniNEthernet::setPowerState(%d, 0x%08lx)\n",
140 (int) powerStateOrdinal
,
141 (UInt32
) whatDevice
);
143 switch ( currentPowerState
)
145 case 0: // Ethernet is off
147 // Shutdown the hardware unconditionally.
150 // Turn off PHY before turning off MAC
151 // MII_CONTROL_POWERDOWN ? no, it is read-only for Broadcom 5201
152 // PHY, but 5400 is R/W
153 stopPHYChip(false); //In this file
155 // Now turn off ethernet clock in Uni-N
156 callPlatformFunction("EnableUniNEthernetClock", true,
157 (void *)false, 0, 0, 0);
160 case kMaxUniNEnetPowerState
: // 1 = max power state, Ethernet is on
162 // Now turn on ethernet clock in Uni-N
163 callPlatformFunction("EnableUniNEthernetClock", true,
164 (void *)true, 0, 0, 0);
166 #if EXTRANEOUS_PM_DELAYS
167 IODelay(MII_DEFAULT_DELAY
* 1000); // 20 milliseconds
170 // Bring up PHY then MAC.
177 // This is illegal, only 0 and 1 are allowed for
178 // UniN ethernet for now
182 return IOPMAckImplied
;
185 // This method sets up the PHY registers for low power.
186 // Copied from stopEthernetController() in OS9.
187 // The setupWOL value is not really implemented systemwide yet
189 UniNEnet::stopPHYChip(bool setupWOL
)
194 if (phyBCMType
== 0) return;
196 //IOLog("UniN on stop phy = %d\n", phyBCMType);
198 if (setupWOL
== false)
200 //disabling MIF interrupts on the 5201 is explicit
201 if (phyBCMType
== 5201)
203 miiWriteWord(0x0000, MII_BCM5201_INTERRUPT
, kPHYAddr0
);
204 // 0 or 0x1f or phyId? miiFindPHY returns any integer
208 //Drive the MDIO line high to prevent immediate wakeup
209 val32
= READ_REGISTER( MIFConfiguration
);
210 WRITE_REGISTER( MIFConfiguration
, val32
& kMIFConfiguration_Poll_Enable
);
212 // 5th ADDR in Broadcom PHY docs
213 miiReadWord( &val16
, MII_LINKPARTNER
, kPHYAddr0
);
215 // don't know why OS9 writes it back unchanged
216 miiWriteWord( val16
, MII_LINKPARTNER
, kPHYAddr0
);
218 /* Put the MDIO pins into a benign state. Note that the management regs
219 in the PHY will be inaccessible. This is to guarantee max power savings
220 on Powerbooks and to eliminate damage to Broadcom PHYs.
223 WRITE_REGISTER( MIFConfiguration
, kMIFConfiguration_BB_Mode
);
225 WRITE_REGISTER( MIFBitBangClock
, 0x0000 );
226 WRITE_REGISTER( MIFBitBangData
, 0x0000 );
227 WRITE_REGISTER( MIFBitBangOutputEnable
, 0x0000 );
228 WRITE_REGISTER( XIFConfiguration
, kXIFConfiguration_GMIIMODE
229 | kXIFConfiguration_MII_Int_Loopback
);
233 //For multicast filtering these bits must be enabled
234 WRITE_REGISTER( RxMACConfiguration
,
235 kRxMACConfiguration_Hash_Filter_Enable
236 | kRxMACConfiguration_Rx_Mac_Enable
);
237 // set kpfRxMACEnabled in OS9, but I don't see matching OS X flag
241 WRITE_REGISTER( RxMACConfiguration
, 0 );
242 // un-set kpfRxMACEnabled in OS9, but I don't see matching OS X flag
245 WRITE_REGISTER( TxMACConfiguration
, 0 );
246 WRITE_REGISTER( XIFConfiguration
, 0 );
249 // Disable interrupt source on the controller.
250 // Already disabled from earlier resetAndEnable(false) call.
251 WRITE_REGISTER( InterruptMask
, kInterruptMask_None
); // all FF
254 WRITE_REGISTER( TxConfiguration
, 0 );
255 WRITE_REGISTER( RxConfiguration
, 0 );
259 // this doesn't power down stuff, but if we don't hit it then we can't
260 // superisolate the transceiver
261 WRITE_REGISTER( SoftwareReset
, kSoftwareReset_TX
| kSoftwareReset_RX
);
263 // kSoftwareReset_RSTOUT too???
266 // IODelay(MII_RESET_DELAY * 1000); // 10 milliseconds
270 IOLog("UniNEnet timeout on SW reset\n");
273 val32
= READ_REGISTER( SoftwareReset
);
274 } while ( (val32
& (kSoftwareReset_TX
| kSoftwareReset_RX
)) != 0 );
276 WRITE_REGISTER( TxMACSoftwareResetCommand
, kTxMACSoftwareResetCommand_Reset
);
277 WRITE_REGISTER( RxMACSoftwareResetCommand
, kRxMACSoftwareResetCommand_Reset
);
279 //This is what actually turns off the LINK LED
280 if (phyBCMType
== 5400)
283 // The 5400 has read/write privilege on this bit,
284 // but 5201 is read-only.
285 miiWriteWord( MII_CONTROL_POWERDOWN
, MII_CONTROL
, kPHYAddr0
);
288 else // Only other possibility is Broadcom 5201 (or 5202?)
291 miiReadWord( &val16
, MII_BCM5201_AUXMODE2
, kPHYAddr0
);
292 miiWriteWord( val16
& ~MII_BCM5201_AUXMODE2_LOWPOWER
,
293 MII_BCM5201_AUXMODE2
, kPHYAddr0
);
296 miiWriteWord( MII_BCM5201_MULTIPHY_SUPERISOLATE
,
297 MII_BCM5201_MULTIPHY
,
300 } // end of none-WOL case
305 UniNEnet::startPHYChip()
310 // if (netifClient) //MacOS 9 uses numClients == 1?
312 //IOLog("UniN on restart phy = %d\n", phyBCMType);
314 val32
= READ_REGISTER( TxConfiguration
);
315 WRITE_REGISTER( TxConfiguration
, val32
| kTxConfiguration_Tx_DMA_Enable
);
317 val32
= READ_REGISTER( RxConfiguration
);
318 WRITE_REGISTER( RxConfiguration
, val32
| kRxConfiguration_Rx_DMA_Enable
);
320 val32
= READ_REGISTER( TxMACConfiguration
);
321 WRITE_REGISTER( TxMACConfiguration
, val32
| kTxMACConfiguration_TxMac_Enable
);
323 val32
= READ_REGISTER( RxMACConfiguration
);
324 WRITE_REGISTER( RxMACConfiguration
,
325 val32
| kRxMACConfiguration_Rx_Mac_Enable
326 | kRxMACConfiguration_Hash_Filter_Enable
);
328 // Set flag to RxMACEnabled somewhere??
330 /* These registers are only for the Broadcom 5201.
331 We write the auto low power mode bit here because if we do it earlier
332 and there is no link then the xcvr registers become unclocked and
335 if (phyBCMType
== 5201)
337 // Ask Enrique why the following 2 lines are not necessary in OS 9.
338 // These 2 lines should take the PHY out of superisolate mode. All
339 // MII inputs are ignored until the PHY is out of isolate mode
340 miiReadWord( &val16
, MII_BCM5201_MULTIPHY
, kPHYAddr0
);
341 miiWriteWord( val16
& ~MII_BCM5201_MULTIPHY_SUPERISOLATE
,
342 MII_BCM5201_MULTIPHY
, kPHYAddr0
);
345 // Automatically go into low power mode if no link
346 miiReadWord( &val16
, MII_BCM5201_AUXMODE2
, kPHYAddr0
);
347 miiWriteWord( val16
| MII_BCM5201_AUXMODE2_LOWPOWER
,
348 MII_BCM5201_AUXMODE2
, kPHYAddr0
);
351 #if EXTRANEOUS_PM_DELAYS
352 IODelay(MII_DEFAULT_DELAY
* 1000); // 20 milliseconds
356 // WARNING... this code is untested on gigabit ethernet (5400), there
357 // should be a case to handle it for MII_CONTROL_POWERDOWN bit here,
358 // unless it is unnecessary after a hardware reset
360 WRITE_REGISTER( RxKick
, RX_RING_LENGTH
- 4 );
364 /*-------------------------------------------------------------------------
365 * Assert the reset pin on the PHY momentarily to initialize it, and also
366 * to bring the PHY out of low-power mode.
368 *-------------------------------------------------------------------------*/
370 bool UniNEnet::resetPHYChip()
374 result
= keyLargo
->callPlatformFunction(keyLargo_resetUniNEthernetPhy
, false, 0, 0, 0, 0);
375 if (result
!= kIOReturnSuccess
) return false;