#include <sys/cdefs.h>
__BEGIN_DECLS
#include <ppc/proc_reg.h>
#include <ppc/machine_routines.h>
#include <mach/mach_types.h>
__END_DECLS
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOKitKeys.h>
#include "MacRISC4PE.h"
static unsigned long macRISC4Speed[] = { 0, 1 };
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/pwr_mgt/IOPMPagingPlexus.h>
#include <IOKit/pwr_mgt/IOPMPowerSource.h>
#include <pexpert/pexpert.h>
extern char *gIOMacRISC4PMTree;
#define super ApplePlatformExpert
OSDefineMetaClassAndStructors(MacRISC4PE, ApplePlatformExpert);
bool MacRISC4PE::start(IOService *provider)
{
long machineType;
char tmpName[32];
OSData *tmpData;
IORegistryEntry *uniNRegEntry,
*spuRegEntry,
*powerMgtEntry;
UInt32 *primInfo;
const OSSymbol *nameValueSymbol;
const OSData *nameValueData;
OSDictionary *pluginDict, *platFuncDict;
bool result, spuNeedsRamFix;
kprintf ("MacRISC4PE::start - entered\n");
setChipSetType(kChipSetTypeCore2001);
provider_name = provider->getName();
machineType = kMacRISC4TypeUnknown;
if (provider_name != NULL) {
if (0 == strncmp(provider_name, "PowerMac", strlen("PowerMac")))
machineType = kMacRISC4TypePowerMac;
else if (0 == strncmp(provider_name, "RackMac", strlen("RackMac")))
machineType = kMacRISC4TypePowerMac;
else if (0 == strncmp(provider_name, "PowerBook", strlen("PowerBook")))
machineType = kMacRISC4TypePowerBook;
else if (0 == strncmp(provider_name, "iBook", strlen("iBook")))
machineType = kMacRISC4TypePowerBook;
else IOLog ("AppleMacRISC4PE - warning: unknown machineType\n");
}
isPortable = (machineType == kMacRISC4TypePowerBook);
setMachineType(machineType);
tmpData = OSDynamicCast(OSData, provider->getProperty("clock-frequency"));
if (tmpData == 0) {
kprintf ("MacRISC4PE::start - no clock-frequency property\n");
return false;
}
macRISC4Speed[0] = *(unsigned long *)tmpData->getBytesNoCopy();
spuNeedsRamFix = true;
spuRegEntry = provider->childFromPath("spu", gIODTPlane);
if (spuRegEntry) {
const UInt32 kProjectPhaseMask = 0xFFFFFF0F; const UInt32 kConvertDevelopmentMask = 0xFFFFFF9F; const UInt32 kDevelopmentPhase = 0xD0;
const UInt32 kEngineeringBuild = 0xE0;
OSData *spuVersionData;
UInt32 minSPUVersion, currentSPUVersion;
UInt32 tempCurrent, tempMin;
minSPUVersion = 0x111f1; spuVersionData = OSDynamicCast (OSData, spuRegEntry->getProperty ("version"));
if (spuVersionData) {
currentSPUVersion = ((unsigned long *)spuVersionData->getBytesNoCopy())[0];
if ((kDevelopmentPhase == (currentSPUVersion & ~kProjectPhaseMask)) ||
(kEngineeringBuild == (currentSPUVersion & ~kProjectPhaseMask)))
tempCurrent = currentSPUVersion & kConvertDevelopmentMask;
else tempCurrent = currentSPUVersion;
if ((kDevelopmentPhase == (minSPUVersion & ~kProjectPhaseMask)) ||
(kEngineeringBuild == (minSPUVersion & ~kProjectPhaseMask)))
tempMin = minSPUVersion & kConvertDevelopmentMask;
else tempMin = minSPUVersion;
if (tempMin <= tempCurrent)
spuNeedsRamFix = false;
spuRegEntry->release();
}
} else
spuNeedsRamFix = false;
if (spuNeedsRamFix) {
uniNRegEntry = provider->childFromPath("u3", gIODTPlane);
if ((uniNRegEntry) &&
(tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("device-rev")))) {
uniNVersion = ((unsigned long *)tmpData->getBytesNoCopy())[0];
IORegistryEntry *cpuRegEntry = NULL;
OSData *cpu0FreqData = NULL;
UInt32 cpu0Freq = 0;
int cpuCount;
const UInt32 one_eight_ghz_freq = 1800000000;
cpuRegEntry = fromPath ("/cpus/@1", gIODTPlane);
if (cpuRegEntry) {
cpuCount = 2;
cpuRegEntry->release();
} else
cpuCount = 1;
cpuRegEntry = fromPath ("/cpus/@0", gIODTPlane);
if(cpuRegEntry) {
cpu0FreqData = OSDynamicCast (OSData, cpuRegEntry->getProperty ("clock-frequency"));
if(cpu0FreqData)
cpu0Freq = *(UInt32 *)cpu0FreqData->getBytesNoCopy();
cpuRegEntry->release();
}
cannotSleep = ((0 == strncmp(provider_name, "PowerMac7,2", strlen("PowerMac7,2"))) && (kUniNRevision3_2_1 == uniNVersion) && (cpuCount == 1) && (one_eight_ghz_freq == cpu0Freq) );
if (cannotSleep) setProperty ("PlatformCannotSleep", true);
uniNRegEntry->release();
}
}
powerMgtEntry = retrievePowerMgtEntry ();
_pePMFeatures = 0;
if (powerMgtEntry) {
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 ("MacRISC4PE: Public PM Features: %0x.\n",_pePMFeatures);
kprintf ("MacRISC4PE: Privat PM Features: %0x.\n",_pePrivPMFeatures);
kprintf ("MacRISC4PE: Num Internal Batteries Supported: %0x.\n", _peNumBatteriesSupported);
}
}
} else kprintf ("MacRISC4PE: no power-mgt information available\n");
pmmutex = IOLockAlloc();
if (pmmutex == NULL)
return false;
else
IOLockInit( pmmutex );
result = super::start(provider);
platFuncDict = OSDictionary::withCapacity(2);
if (platFuncDict) {
strcpy(tmpName, "IOPlatformFunctionNub");
nameValueSymbol = OSSymbol::withCString(tmpName);
nameValueData = OSData::withBytes(tmpName, strlen(tmpName)+1);
platFuncDict->setObject ("name", nameValueData);
platFuncDict->setObject ("compatible", nameValueData);
if (plFuncNub = IOPlatformExpert::createNub (platFuncDict)) {
if (!plFuncNub->attach( this ))
IOLog ("NUB ATTACH FAILED for IOPlatformFunctionNub\n");
plFuncNub->setName (nameValueSymbol);
plFuncNub->registerService();
}
platFuncDict->release();
nameValueSymbol->release();
nameValueData->release();
} else return false;
OSDictionary* pluginLookupDict;
if ( ( pluginLookupDict = OSDynamicCast( OSDictionary, getProperty( "IOPlatformPluginTable" ) ) ) == NULL )
{
kprintf( "CANNOT LOAD PLATFORM-PLUGIN LOOKUP TABLE\n" );
return( false );
}
removeProperty( "IOPlatformPluginTable" );
OSString* platformPluginNameString;
OSData* platformPluginNameData;
const char* platformPluginName = "MacRISC4_PlatformPlugin";
OSString* modelString;
if ( ( platformPluginNameString = OSDynamicCast( OSString, pluginLookupDict->getObject( provider_name ) ) ) != NULL )
{
platformPluginName = platformPluginNameString->getCStringNoCopy();
}
platformPluginNameData = OSData::withBytes( platformPluginName, strlen( platformPluginName ) + 1 );
if ( ( pluginDict = OSDictionary::withCapacity( 3 ) ) == NULL )
return( false );
const char* ioPlatformPluginString = "IOPlatformPlugin";
nameValueData = OSData::withBytes( ioPlatformPluginString, strlen( ioPlatformPluginString ) + 1 );
modelString = OSString::withCString( provider_name );
pluginDict->setObject( "name", nameValueData );
pluginDict->setObject( "compatible", platformPluginNameData );
pluginDict->setObject( "model", modelString );
nameValueData->release();
platformPluginNameData->release();
if ( ( ioPPluginNub = IOPlatformExpert::createNub( pluginDict ) ) != NULL )
{
if ( !ioPPluginNub->attach( this ) )
kprintf( "NUB ATTACH FAILED\n" );
ioPPluginNub->setName( ioPlatformPluginString );
ioPPluginNub->registerService();
}
pluginDict->release();
modelString->release();
kprintf ("MacRISC4PE::start - done\n");
return result;
}
IORegistryEntry * MacRISC4PE::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 MacRISC4PE::platformAdjustService(IOService *service)
{
const OSSymbol *keySymbol;
OSSymbol *tmpSymbol;
bool result;
IORegistryEntry *parentIC;
OSData *parentICData;
#if 1 // VESTA HACK - remove this code once a better solution for resetting the phy!!
IORegistryEntry *phy;
OSData *compat;
static IOService *macio;
static bool hasVesta;
if (IODTMatchNubWithKeys(service, "mac-io")) {
macio = service; if (hasVesta)
macio->setProperty ("hasVesta", hasVesta);
return true;
}
if (IODTMatchNubWithKeys(service, "K2-GMAC") || IODTMatchNubWithKeys(service, "gmac")) {
service->setProperty("IOPMPCIConfigSpaceVolatile", kOSBooleanFalse);
phy = service->getChildEntry( gIODTPlane );
if (phy) {
compat = OSDynamicCast (OSData, phy->getProperty ("compatible"));
if (compat && (strncmp ( ( const char * ) compat->getBytesNoCopy(), "B5221", strlen ("B5221")))) {
hasVesta = true;
if (macio)
macio->setProperty ("hasVesta", hasVesta);
}
}
return true;
}
#endif
if (IODTMatchNubWithKeys(service, "cpu"))
{
parentICData = OSDynamicCast(OSData, service->getProperty(kMacRISC4ParentICKey));
if (parentICData == 0)
{
parentIC = fromPath("mac-io/mpic", gIODTPlane);
parentICData = OSDynamicCast(OSData, parentIC->getProperty("AAPL,phandle"));
service->setProperty(kMacRISC4ParentICKey, parentICData);
}
service->setProperty ("cpu-device-type", "MacRISC4CPU");
return true;
}
if (IODTMatchNubWithKeys(service, "open-pic"))
{
keySymbol = OSSymbol::withCStringNoCopy("InterruptControllerName");
tmpSymbol = (OSSymbol *)IODTInterruptControllerName(service);
result = service->setProperty(keySymbol, tmpSymbol);
return true;
}
if (IODTMatchNubWithKeys(service, "K2-GMAC") || IODTMatchNubWithKeys(service, "gmac"))
{
service->setProperty("IOPMPCIConfigSpaceVolatile", kOSBooleanFalse);
return true;
}
if (!strcmp(service->getName(), "programmer-switch"))
{
service->setProperty("mask_NMI", service);
return true;
}
if (!strcmp(service->getName(), "pmu"))
{
OSArray *tmpArray;
OSCollectionIterator *extIntList, *extIntListOldWay;
IORegistryEntry *extInt = NULL;
OSObject *extIntControllerName;
OSObject *extIntControllerData;
service->setProperty("no-nvram", service);
extIntList = extIntListOldWay = NULL;
extIntList = IODTFindMatchingEntries(getProvider(), kIODTRecursive, "'pmu-interrupt'");
if (extIntList) {
extInt = (IORegistryEntry *)extIntList->getNextObject();
if (extInt)
kprintf ("pmu - got pmu-interrupt node new way - name '%s'\n", extInt->getName());
else {
extIntListOldWay = IODTFindMatchingEntries(getProvider(), kIODTRecursive, "'extint-gpio1'");
extInt = (IORegistryEntry *)extIntListOldWay->getNextObject();
if (extInt)
kprintf ("pmu - got pmu-interrupt node old way - name '%s'\n", extInt->getName());
else
panic ("MacRISC4PE::platformAdjustService - no interrupt information for pmu");
}
}
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);
if (extIntList) extIntList->release();
if (extIntListOldWay) extIntListOldWay->release();
return true;
}
if (!strcmp(service->getName(), "via-pmu"))
{
service->setProperty("BusSpeedCorrect", this);
return true;
}
return true;
}
IOReturn MacRISC4PE::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("PlatformIsPortable")) {
*(bool *) param1 = isPortable;
return kIOReturnSuccess;
}
return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
}
void MacRISC4PE::getDefaultBusSpeeds(long *numSpeeds, unsigned long **speedList)
{
if ((numSpeeds == 0) || (speedList == 0)) return;
*numSpeeds = 1;
*speedList = macRISC4Speed;
}
void MacRISC4PE::PMInstantiatePowerDomains ( void )
{
IOPMUSBMacRISC4 * usbMacRISC4;
const OSSymbol *desc = OSSymbol::withCString("powertreedesc");
kprintf ("MacRISC4PE::PMInstantiatePowerDomains - getting pmtree property\n");
thePowerTree = OSDynamicCast(OSArray, getProperty(desc));
if( 0 == thePowerTree)
{
kprintf ("error retrieving power tree\n");
return;
}
kprintf ("MacRISC4PE::PMInstantiatePowerDomains - got pmtree property\n");
getProvider()->setProperty (desc, thePowerTree);
removeProperty(desc);
root = IOPMrootDomain::construct();
root->attach(this);
root->start(this);
if (cannotSleep) {
root->setSleepSupported(kPCICantSleep);
} else {
root->setSleepSupported(kRootDomainSleepSupported);
}
if (NULL == root)
{
kprintf ("PMInstantiatePowerDomains - null ROOT\n");
return;
}
PMRegisterDevice (NULL, root);
usbMacRISC4 = new IOPMUSBMacRISC4;
if (usbMacRISC4)
{
usbMacRISC4->init ();
usbMacRISC4->attach (this);
usbMacRISC4->start (this);
PMRegisterDevice (root, usbMacRISC4);
}
slotsMacRISC4 = new IOPMSlotsMacRISC4;
if (slotsMacRISC4)
{
slotsMacRISC4->init ();
slotsMacRISC4->attach (this);
slotsMacRISC4->start (this);
PMRegisterDevice (root, slotsMacRISC4);
}
return;
}
extern const IORegistryPlane * gIOPowerPlane;
void MacRISC4PE::PMRegisterDevice(IOService * theNub, IOService * theDevice)
{
bool nodeFound = false;
IOReturn err = -1;
OSData * propertyPtr = 0;
const char * theProperty;
if (pmmutex != NULL)
IOLockLock(pmmutex);
multipleParentKeyValue = NULL;
numInstancesRegistered = 0;
nodeFound = CheckSubTree (thePowerTree, theNub, theDevice, NULL);
if (0 == numInstancesRegistered) {
while( theNub && (!theNub->inPlane(gIOPowerPlane)))
theNub = theNub->getProvider();
}
if (pmmutex != NULL)
IOLockUnlock(pmmutex);
if ( NULL != theNub )
err = theNub->addPowerChild (theDevice);
if ((err != IOPMNoErr) && (0 == numInstancesRegistered) && (theDevice != root)) {
root->addPowerChild (theDevice);
}
propertyPtr = OSDynamicCast(OSData,theDevice->getProperty("AAPL,slot-name"));
if ( propertyPtr ) {
theProperty = (const char *) propertyPtr->getBytesNoCopy();
if ( strncmp("SLOT-",theProperty,5) == 0 )
slotsMacRISC4->addPowerChild (theDevice);
}
return;
}