#include <sys/cdefs.h>
__BEGIN_DECLS
#include <ppc/proc_reg.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/IOPMPowerSource.h>
#include <pexpert/pexpert.h>
extern char *gIOMacRISC4PMTree;
#ifndef kIOHibernateFeatureKey
#define kIOHibernateFeatureKey "Hibernation"
#endif
#define super ApplePlatformExpert
OSDefineMetaClassAndStructors(MacRISC4PE, ApplePlatformExpert);
bool MacRISC4PE::start(IOService *provider)
{
long machineType;
char tmpName[32];
OSData *tmpData;
IORegistryEntry *uniNRegEntry,
*spuRegEntry,
*powerMgtEntry,
* aCPURegEntry;
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)
{
OSData * cpu0FreqData = NULL;
UInt32 cpu0Freq = 0;
int cpuCount;
const UInt32 one_eight_ghz_freq = 1800000000;
uniNRegEntry = provider->childFromPath("u3", gIODTPlane);
if ((uniNRegEntry) && (tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("device-rev"))))
{
uniNVersion = ((unsigned long *)tmpData->getBytesNoCopy())[0];
aCPURegEntry = fromPath ("/cpus/@1", gIODTPlane);
if (aCPURegEntry) {
cpuCount = 2; aCPURegEntry->release();
} else
cpuCount = 1;
aCPURegEntry = fromPath ("/cpus/@0", gIODTPlane);
if( aCPURegEntry )
{
cpu0FreqData = OSDynamicCast (OSData, aCPURegEntry->getProperty ("clock-frequency"));
if(cpu0FreqData)
cpu0Freq = *(UInt32 *)cpu0FreqData->getBytesNoCopy();
aCPURegEntry->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 );
IORegistryEntry * regEntry = IORegistryEntry::fromPath("/u3/dart", gIODTPlane);
if (!regEntry)
regEntry = IORegistryEntry::fromPath("/u4/dart", gIODTPlane);
if (regEntry) {
setProperty(kIOPlatformMapperPresentKey, kOSBooleanTrue);
regEntry->release();
}
regEntry = IORegistryEntry::fromPath("/u3/mpic", gIODTPlane);
if (!regEntry)
regEntry = IORegistryEntry::fromPath("/u4/mpic", gIODTPlane);
if (regEntry) {
u3IsHostMPIC = (regEntry->getProperty ("interrupts") == NULL);
regEntry->release();
}
result = super::start(provider);
platFuncDict = OSDictionary::withCapacity(2);
if (platFuncDict)
{
strncpy(tmpName, "IOPlatformFunctionNub", sizeof( "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;
OSData * pHandle;
const OSSymbol * pHandleKey;
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();
pHandleKey = OSSymbol::withCStringNoCopy("AAPL,phandle");
if (pHandle = OSDynamicCast (OSData, provider->getProperty (pHandleKey)))
pluginDict->setObject (pHandleKey, pHandle);
pHandleKey->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();
{
OSDictionary * propTable;
OSCollectionIterator * propIter;
OSSymbol * propKey;
OSData * propData;
propTable = NULL;
propIter = NULL;
if ( ((propTable = provider->dictionaryWithProperties()) == 0) ||
((propIter = OSCollectionIterator::withCollection( propTable )) == 0) )
{
if ( propTable )
propTable->release();
propTable = NULL;
}
if ( propTable )
{
while ( (propKey = OSDynamicCast(OSSymbol, propIter->getNextObject())) != 0 )
{
if ( strncmp( kFunctionRequiredPrefix, propKey->getCStringNoCopy(), strlen(kFunctionRequiredPrefix)) == 0)
{
if (strncmp(kFunctionProvidedPrefix, propKey->getCStringNoCopy(), strlen(kFunctionProvidedPrefix)) == 0)
continue;
propData = OSDynamicCast(OSData, propTable->getObject(propKey));
if (propData)
{
if ( ioPPluginNub->setProperty (propKey, propData) )
provider->removeProperty (propKey);
}
}
}
}
if (propTable) propTable->release();
if (propIter) propIter->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"))
{
if (!(service->getProperty(gIOInterruptControllersKey)))
{
parentICData = OSDynamicCast(OSData, service->getProperty(kMacRISC4ParentICKey));
if (parentICData == 0)
{
parentIC = fromPath("mac-io/mpic", gIODTPlane);
if (parentIC)
{
parentICData = OSDynamicCast(OSData, parentIC->getProperty("AAPL,phandle"));
service->setProperty(kMacRISC4ParentICKey, parentICData);
parentIC->release();
}
}
}
service->setProperty ("cpu-device-type", "MacRISC4CPU");
return true;
}
if (IODTMatchNubWithKeys(service, "open-pic"))
{
if (u3IsHostMPIC && (service->getProperty ("big-endian") == NULL))
return false;
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 ( strncmp( service->getName(), "pci80211", sizeof( "pci80211" ) ) == 0 )
{
if ( strncmp( provider_name, "PowerMac8,1", sizeof( "PowerMac8,1" ) ) == 0 )
{
if ( service->getProperty( "NCWI" ) == NULL )
{
static const unsigned char NcwiPropertyData[ 2 ] = { 0x01, 0x01 };
service->setProperty( "NCWI", ( void * ) NcwiPropertyData, sizeof( NcwiPropertyData ) );
return( true );
}
}
}
if ( strncmp( service->getName(), "smu", sizeof( "smu" ) ) == 0 )
{
OSString *platformModel;
platformModel = OSString::withCString (provider_name);
if (platformModel) {
service->setProperty("platform-model", platformModel);
platformModel->release();
}
if ( strncmp( provider_name, "PowerMac8,1", sizeof( "PowerMac8,1" ) ) == 0 )
{
if ( service->getProperty( "sleep-led-limits" ) == NULL )
{
service->setProperty( "sleep-led-limits", ( void * ) NULL, 0 );
}
}
return( true );
}
if ( strncmp(service->getName(), "pmu", sizeof( "pmu" ) ) == 0 )
{
OSArray *tmpArray, *tmpArrayCopy;
OSCollectionIterator *extIntList, *extIntListOldWay;
IORegistryEntry *extInt = NULL;
OSObject *extIntControllerName;
OSObject *extIntControllerData;
OSString *platformModel;
service->setProperty("no-nvram", service);
platformModel = OSString::withCString (provider_name);
if (platformModel) {
service->setProperty("platform-model", platformModel);
platformModel->release();
}
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);
tmpArrayCopy = (OSArray *) tmpArray->copyCollection(); tmpArrayCopy->replaceObject(4, extIntControllerName);
service->setProperty(gIOInterruptControllersKey, tmpArrayCopy); tmpArrayCopy->release();
tmpArray = (OSArray *)service->getProperty(gIOInterruptSpecifiersKey);
tmpArrayCopy = (OSArray *) tmpArray->copyCollection(); tmpArrayCopy->replaceObject(4, extIntControllerData);
service->setProperty(gIOInterruptSpecifiersKey, tmpArrayCopy); tmpArrayCopy->release();
if (extIntList) extIntList->release();
if (extIntListOldWay) extIntListOldWay->release();
return true;
}
if ( strncmp(service->getName(), "via-pmu", sizeof( "via-pmu" )) == 0 )
{
service->setProperty("BusSpeedCorrect", this);
return true;
}
if ( ( strncmp(service->getName(), "pci", sizeof( "pci" ) ) == 0) && service->getProperty ("shasta-interrupt-sequencer"))
{
publishResource ("ht-interrupt-sequencer", service);
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;
}
if (functionName->isEqualTo("IOPMSetSleepSupported")) {
return slotsMacRISC4->determineSleepSupport ();
}
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;
UInt32 hibEnable;
OSArray *tmpArray;
const OSSymbol *desc = OSSymbol::withCString("powertreedesc");
kprintf ("MacRISC4PE::PMInstantiatePowerDomains - getting pmtree property\n");
tmpArray = OSDynamicCast(OSArray, getProperty(desc));
if ( tmpArray )
thePowerTree = (OSArray *)tmpArray->copyCollection();
else
thePowerTree = NULL;
if( 0 == thePowerTree)
{
kprintf ("error retrieving power tree\n");
return;
}
kprintf ("MacRISC4PE::PMInstantiatePowerDomains - got pmtree property\n");
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;
}
if (PE_parse_boot_arg("hib", &hibEnable) && hibEnable)
{
root->publishFeature(kIOHibernateFeatureKey);
}
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( theProperty, "SLOT-", strlen("SLOT-")) == 0 )
slotsMacRISC4->addPowerChild (theDevice);
}
return;
}