#include <ppc/proc_reg.h>
#include <ppc/machine_routines.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOKitKeys.h>
#include "Core99.h"
#include <IOKit/pci/IOPCIDevice.h>
static unsigned long core99Speed[] = { 0, 1 };
#include <IOKit/pwr_mgt/RootDomain.h>
#include "IOPMSlots99.h"
#include "IOPMUSB99.h"
extern char * gIOCore99PMTree;
#define super ApplePlatformExpert
OSDefineMetaClassAndStructors(Core99PE, ApplePlatformExpert);
bool Core99PE::start(IOService *provider)
{
long machineType;
long allInOne;
OSData *tmpData;
IORegistryEntry *uniNRegEntry;
IORegistryEntry *powerMgtEntry;
unsigned long *primInfo;
unsigned long uniNArbCtrl, uniNBaseAddressTemp;
setChipSetType(kChipSetTypeCore99);
if (!strcmp(provider->getName(), "PowerMac2,1"))
machineType = kCore99TypePowerMac2_1;
else if (!strcmp(provider->getName(), "PowerMac2,2"))
machineType = kCore99TypePowerMac2_2;
else if (!strcmp(provider->getName(), "PowerMac3,1"))
machineType = kCore99TypePowerMac3_1;
else if (!strcmp(provider->getName(), "PowerMac3,2"))
machineType = kCore99TypePowerMac3_2;
else if (!strcmp(provider->getName(), "PowerMac3,3"))
machineType = kCore99TypePowerMac3_3;
else if (!strcmp(provider->getName(), "PowerMac5,1"))
machineType = kCore99TypePowerMac5_1;
else if (!strcmp(provider->getName(), "PowerBook2,1"))
machineType = kCore99TypePowerBook2_1;
else if (!strcmp(provider->getName(), "PowerBook2,2"))
machineType = kCore99TypePowerBook2_2;
else if (!strcmp(provider->getName(), "PowerBook3,1"))
machineType = kCore99TypePowerBook3_1;
else return false;
setMachineType(machineType);
allInOne = 0;
switch (getMachineType()) {
case kCore99TypePowerMac2_1 :
case kCore99TypePowerMac2_2 :
allInOne = 1;
break;
}
if (allInOne) setProperty("AllInOne", this);
tmpData = OSDynamicCast(OSData, provider->getProperty("clock-frequency"));
if (tmpData == 0) return false;
core99Speed[0] = *(unsigned long *)tmpData->getBytesNoCopy();
uniNRegEntry = provider->childFromPath("uni-n", gIODTPlane);
if (uniNRegEntry == 0) return false;
tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("reg"));
if (tmpData == 0) return false;
uniNBaseAddressTemp = ((unsigned long *)tmpData->getBytesNoCopy())[0];
uniNBaseAddress = (unsigned long *)ml_io_map(uniNBaseAddressTemp, 0x1000);
if (uniNBaseAddress == 0) return false;
uniNVersion = readUniNReg(kUniNVersion);
uniNArbCtrl = readUniNReg(kUniNArbCtrl);
uniNArbCtrl &= ~kUniNArbCtrlQAckDelayMask;
if (uniNVersion < kUniNVersion107) {
uniNArbCtrl |= kUniNArbCtrlQAckDelay105 << kUniNArbCtrlQAckDelayShift;
} else {
uniNArbCtrl |= kUniNArbCtrlQAckDelay << kUniNArbCtrlQAckDelayShift;
}
writeUniNReg(kUniNArbCtrl, uniNArbCtrl);
IOService *uniNServiceEntry = OSDynamicCast(IOService, uniNRegEntry);
if (uniNServiceEntry != NULL)
createNubs(this, uniNRegEntry->getChildIterator( gIODTPlane ));
powerMgtEntry = retrievePowerMgtEntry ();
if (powerMgtEntry == 0) {
kprintf ("didn't find power mgt node\n");
return false;
}
tmpData = OSDynamicCast(OSData, powerMgtEntry->getProperty ("prim-info"));
if (tmpData != 0) {
primInfo = (unsigned long *)tmpData->getBytesNoCopy();
if (primInfo != 0) {
_pePMFeatures = primInfo[3];
_pePrivPMFeatures = primInfo[4];
_peNumBatteriesSupported = ((primInfo[6]>>16) & 0x000000FF);
kprintf ("Public PM Features: %0x.\n",_pePMFeatures);
kprintf ("Privat PM Features: %0x.\n",_pePrivPMFeatures);
kprintf ("Num Internal Batteries Supported: %0x.\n", _peNumBatteriesSupported);
}
}
mutex = IOLockAlloc();
if (mutex == NULL) {
return false;
}
else
IOLockInit( mutex );
return super::start(provider);
}
IORegistryEntry * Core99PE::retrievePowerMgtEntry (void)
{
IORegistryEntry * theEntry = 0;
IORegistryEntry * anObj = 0;
IORegistryIterator * iter;
OSString * powerMgtNodeName;
iter = IORegistryIterator::iterateOver (IORegistryEntry::getPlane(kIODeviceTreePlane), kIORegistryIterateRecursively);
if (iter) {
powerMgtNodeName = OSString::withCString("power-mgt");
anObj = iter->getNextObject ();
while (anObj) {
if (anObj->compareName(powerMgtNodeName)) {
theEntry = anObj;
break;
}
anObj = iter->getNextObject();
}
powerMgtNodeName->release();
iter->release ();
}
return theEntry;
}
bool Core99PE::platformAdjustService(IOService *service)
{
const OSSymbol *tmpSymbol, *keySymbol;
bool result;
if (IODTMatchNubWithKeys(service, "open-pic")) {
keySymbol = OSSymbol::withCStringNoCopy("InterruptControllerName");
tmpSymbol = IODTInterruptControllerName(service);
result = service->setProperty(keySymbol, tmpSymbol);
return true;
}
if (!strcmp(service->getName(), "programmer-switch")) {
service->setProperty("mask_NMI", service); return true;
}
if (!strcmp(service->getName(), "pmu")) {
OSArray *tmpArray;
OSCollectionIterator *extIntList;
IORegistryEntry *extInt;
OSObject *extIntControllerName;
OSObject *extIntControllerData;
service->setProperty("no-nvram", service);
extIntList = IODTFindMatchingEntries(getProvider(), kIODTRecursive,
"'extint-gpio1'");
extInt = (IORegistryEntry *)extIntList->getNextObject();
tmpArray = (OSArray *)extInt->getProperty(gIOInterruptControllersKey);
extIntControllerName = tmpArray->getObject(0);
tmpArray = (OSArray *)extInt->getProperty(gIOInterruptSpecifiersKey);
extIntControllerData = tmpArray->getObject(0);
tmpArray = (OSArray *)service->getProperty(gIOInterruptControllersKey);
tmpArray->replaceObject(4, extIntControllerName);
tmpArray = (OSArray *)service->getProperty(gIOInterruptSpecifiersKey);
tmpArray->replaceObject(4, extIntControllerData);
extIntList->release();
return true;
}
if (!strcmp(service->getName(), "via-pmu")) {
service->setProperty("BusSpeedCorrect", this);
return true;
}
if (getMachineType() == kCore99TypePowerBook3_1) {
if (!strcmp(service->getName(), "ATY,RageM3pParent")) {
if (kIOReturnSuccess == IONDRVLibrariesInitialize(service)) {
createNubs(this, service->getChildIterator( gIODTPlane ));
}
return true;
}
}
if ( strcmp(service->getName(), "usb") == 0 ) {
service->setProperty("USBclock","");
return true;
}
return true;
}
IOReturn Core99PE::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
if (functionName == gGetDefaultBusSpeedsKey) {
getDefaultBusSpeeds((long *)param1, (unsigned long **)param2);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableUniNEthernetClock")) {
enableUniNEthernetClock((bool)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableFireWireClock")) {
enableUniNFireWireClock((bool)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableFireWireCablePower")) {
enableUniNFireWireCablePower((bool)param1);
return kIOReturnSuccess;
}
return super::callPlatformFunction(functionName, waitForFunction,
param1, param2, param3, param4);
}
unsigned long Core99PE::readUniNReg(unsigned long offest)
{
return uniNBaseAddress[offest / 4];
}
void Core99PE::writeUniNReg(unsigned long offest, unsigned long data)
{
uniNBaseAddress[offest / 4] = data;
eieio();
}
void Core99PE::getDefaultBusSpeeds(long *numSpeeds,
unsigned long **speedList)
{
if ((numSpeeds == 0) || (speedList == 0)) return;
*numSpeeds = 1;
*speedList = core99Speed;
}
void Core99PE::enableUniNEthernetClock(bool enable)
{
unsigned long regTemp;
regTemp = readUniNReg(kUniNClockControl);
if (enable) {
regTemp |= kUniNEthernetClockEnable;
} else {
regTemp &= ~kUniNEthernetClockEnable;
}
writeUniNReg(kUniNClockControl, regTemp);
}
void Core99PE::enableUniNFireWireClock(bool enable)
{
unsigned long regTemp;
regTemp = readUniNReg(kUniNClockControl);
IOLog("FWClock, enable = %d kFW = %x\n", enable, kUniNFirewireClockEnable);
if (enable) {
regTemp |= kUniNFirewireClockEnable;
} else {
regTemp &= ~kUniNFirewireClockEnable;
}
writeUniNReg(kUniNClockControl, regTemp);
}
void Core99PE::enableUniNFireWireCablePower(bool enable)
{
long x = getMachineType();
if(x == kCore99TypePowerBook2_2 ||
x == kCore99TypePowerBook3_1 ) {
IOService *keyLargo;
keyLargo = waitForService(serviceMatching("KeyLargo"));
if(keyLargo) {
UInt32 gpioOffset = 0x73;
keyLargo->callPlatformFunction(OSSymbol::withCString("keyLargo_writeRegUInt8"),
true, (void *)&gpioOffset, (void *)(enable ? 0:4), 0, 0);
}
}
}
void Core99PE::PMInstantiatePowerDomains ( void )
{
OSString * errorStr = new OSString;
OSObject * obj;
IOPMUSB99 * usb99;
IOPMSlots99 * slots99;
obj = OSUnserializeXML (gIOCore99PMTree, &errorStr);
if( 0 == (thePowerTree = ( OSArray * ) obj) ) {
kprintf ("error parsing power tree: %s", errorStr->getCStringNoCopy());
}
getProvider()->setProperty ("powertreedesc", thePowerTree);
root = new IOPMrootDomain;
root->init();
root->attach(this);
root->start(this);
root->youAreRoot();
switch (getMachineType()) {
case kCore99TypePowerBook2_1 :
case kCore99TypePowerBook2_2 :
case kCore99TypePowerBook3_1 :
root->setSleepSupported(kRootDomainSleepSupported);
break;
case kCore99TypePowerMac2_1 :
case kCore99TypePowerMac2_2 :
case kCore99TypePowerMac3_1 :
case kCore99TypePowerMac3_2 :
case kCore99TypePowerMac3_3 :
case kCore99TypePowerMac5_1 :
root->setSleepSupported(kRootDomainSleepSupported
| kFrameBufferDeepSleepSupported);
break;
default :
break;
}
if (NULL == root) {
kprintf ("PMInstantiatePowerDomains - null ROOT\n");
return;
}
PMRegisterDevice (NULL, root);
usb99 = new IOPMUSB99;
if (usb99) {
usb99->init ();
usb99->attach (this);
usb99->start (this);
PMRegisterDevice (root, usb99);
}
slots99 = new IOPMSlots99;
if (slots99) {
slots99->init ();
slots99->attach (this);
slots99->start (this);
PMRegisterDevice (root, slots99);
}
}
extern const IORegistryPlane * gIOPowerPlane;
void Core99PE::PMRegisterDevice(IOService * theNub, IOService * theDevice)
{
OSData * aString;
bool nodeFound = false;
IOReturn err = -1;
if (mutex != NULL)
IOLockLock(mutex);
multipleParentKeyValue = NULL;
numInstancesRegistered = 0;
nodeFound = CheckSubTree (thePowerTree, theNub, theDevice, NULL);
if ( ((getMachineType() == kCore99TypePowerMac3_1) ||
(getMachineType() == kCore99TypePowerMac3_2) ||
(getMachineType() == kCore99TypePowerMac3_3)) &&
(OSDynamicCast(IOPCIDevice, theDevice)) ) {
aString = (OSData *)theDevice->getProperty("AAPL,slot-name");
if ( (aString != NULL) && (0 != strncmp(aString->getBytesNoCopy(), "SLOT-A", strlen("SLOT-A"))) )
root->setSleepSupported(kRootDomainSleepNotSupported | kFrameBufferDeepSleepSupported);
}
if (0 == numInstancesRegistered) {
if( theNub && (0 == strncmp(theNub->getName(), "ATY,RageM3p", strlen("ATY,RageM3p"))) &&
(0 != strncmp(theNub->getName(), "ATY,RageM3p1", strlen("ATY,RageM3p1"))) )
theNub = (IOService *) theNub->getParentEntry(gIODTPlane);
while( theNub && (!theNub->inPlane(gIOPowerPlane)))
theNub = theNub->getProvider();
}
if (mutex != NULL)
IOLockUnlock(mutex);
if ( NULL != theNub )
err = theNub->addPowerChild (theDevice);
if ((err != IOPMNoErr) && (0 == numInstancesRegistered) && (theDevice != root))
root->addPowerChild (theDevice);
}