/* * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * DRI: Dave Radcliffe * */ // $Log: MacRISC4PE.cpp,v $ // Revision 1.8 2003/07/22 01:25:53 raddog // [3332537]Fix Ethernet sleep hang by signalling its nub to not save/restore config space (causing a hang if the Ethernet clock is off) // // Revision 1.7 2003/06/27 00:45:07 raddog // [3304596]: remove unnecessary access to U3 Pwr registers on wake, [3249029]: Disable unused second process on wake, [3301232]: remove unnecessary PCI code from PE // // Revision 1.6 2003/06/03 01:53:01 raddog // 3232168, 3259590 - pmu-interrupt map crash fix, cpu driver only load on MacRISC4 // // Revision 1.5 2003/05/10 06:50:29 eem // All sensor functionality included for PowerMac7_2_PlatformPlugin. Version // is 1.0.1d12. // // Revision 1.4.2.1 2003/05/01 09:28:32 eem // Initial check-in in progress toward first Q37 checkpoint. // // Revision 1.4 2003/04/27 23:13:30 raddog // MacRISC4PE.cpp // // Revision 1.3 2003/04/14 20:05:27 raddog // [3224952]AppleMacRISC4CPU must specify which MPIC to use (improved fix over that previously submitted) // // Revision 1.2 2003/02/18 00:02:01 eem // 3146943: timebase enable for MP, bump version to 1.0.1d3. // // Revision 1.1.1.1 2003/02/04 00:36:43 raddog // initial import into CVS // #include __BEGIN_DECLS #include #include /* Map memory map IO space */ #include __END_DECLS #include #include #include "MacRISC4PE.h" //#include static unsigned long macRISC4Speed[] = { 0, 1 }; #include //XXX-#include "IOPMSlotsMacRISC4.h" //XXX-#include "IOPMUSBMacRISC4.h" #include #include #include extern char *gIOMacRISC4PMTree; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define super ApplePlatformExpert OSDefineMetaClassAndStructors(MacRISC4PE, ApplePlatformExpert); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ bool MacRISC4PE::start(IOService *provider) { long machineType; char compatStr[128]; char tmpName[32]; OSData *tmpData; // IORegistryEntry *uniNRegEntry; IORegistryEntry *powerMgtEntry; UInt32 *primInfo; const OSSymbol *nameKey, *compatKey, *nameValueSymbol; const OSData *nameValueData, *compatValueData; OSDictionary *pluginDict, *platFuncDict; bool result; kprintf ("MacRISC4PE::start - entered\n"); setChipSetType(kChipSetTypeCore2001); // Set the machine type. 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 // kMacRISC4TypeUnknown IOLog ("AppleMacRISC4PE - warning: unknown machineType\n"); } isPortable = (machineType == kMacRISC4TypePowerBook); setMachineType(machineType); // Get the bus speed from the Device Tree. 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(); #if 0 // get uni-N version for use by platformAdjustService uniNRegEntry = provider->childFromPath("uni-n", gIODTPlane); if (uniNRegEntry == 0) { kprintf ("MacRISC4PE::start - no uni-n\n"); return false; } tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("device-rev")); if (tmpData == 0) return false; uniNVersion = ((unsigned long *)tmpData->getBytesNoCopy())[0]; #endif // Get PM features and private features 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); } } // This is to make sure that is PMRegisterDevice reentrant pmmutex = IOLockAlloc(); if (pmmutex == NULL) return false; else IOLockInit( pmmutex ); /* * Call super::start *before* we create specialized child nubs. Child drivers for these nubs * want to call publishResource and publishResource needs the IOResources node to exist * if not we'll get a message like "not registry member at registerService()" * super::start() takes care of creating IOResources */ result = super::start(provider); nameKey = OSSymbol::withCStringNoCopy("name"); compatKey = OSSymbol::withCStringNoCopy("compatible"); // Create PlatformFunction nub platFuncDict = OSDictionary::withCapacity(2); if (platFuncDict) { strcpy(tmpName, "IOPlatformFunctionNub"); nameValueSymbol = OSSymbol::withCString(tmpName); nameValueData = OSData::withBytes(tmpName, strlen(tmpName)+1); platFuncDict->setObject (nameKey, nameValueData); platFuncDict->setObject (compatKey, 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; /* * Create PlatformPlugin nub - for specialized plugins, the compatible property is of the * form provider_name_PlatformPlugin, e.g., PowerMac7_1_PlatformPlugin. For all others * a generic compatible property of "MacRISC4_PlatformPlugin" is created. */ if (!strcmp (provider_name, "PowerMac7,2") /* add others here */) strcpy (compatStr, "PowerMac7_2"); else // generic plugin strcpy (compatStr, "MacRISC4"); pluginDict = OSDictionary::withCapacity(2); if (pluginDict) { strcpy(tmpName, "IOPlatformPlugin"); nameValueSymbol = OSSymbol::withCString(tmpName); nameValueData = OSData::withBytes(tmpName, strlen(tmpName)+1); pluginDict->setObject (nameKey, nameValueData); strcat (compatStr, "_PlatformPlugin"); compatValueData = OSData::withBytes(compatStr, strlen(compatStr)+1); pluginDict->setObject (compatKey, compatValueData); if (ioPPluginNub = IOPlatformExpert::createNub (pluginDict)) { if (!ioPPluginNub->attach( this )) kprintf ("NUB ATTACH FAILED\n"); ioPPluginNub->setName (nameValueSymbol); ioPPluginNub->registerService(); } pluginDict->release(); nameValueSymbol->release(); nameValueData->release(); compatValueData->release(); } else return false; nameKey->release(); compatKey->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 (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); } // Identify this as a MacRISC4 type cpu so cpu matching works correctly 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")) { // [3332537] Mark ethernet PCI space as non-volatile (not needing save/restore) service->setProperty("IOPMPCIConfigSpaceVolatile", kOSBooleanFalse); return true; } if (!strcmp(service->getName(), "programmer-switch")) { // Set property to tell AppleNMI to mask/unmask NMI @ sleep/wake service->setProperty("mask_NMI", service); return true; } if (!strcmp(service->getName(), "pmu")) { // Change the interrupt mapping for pmu source 4. OSArray *tmpArray; OSCollectionIterator *extIntList, *extIntListOldWay; IORegistryEntry *extInt; OSObject *extIntControllerName; OSObject *extIntControllerData; // Set the no-nvram property. service->setProperty("no-nvram", service); extIntList = extIntListOldWay = NULL; // Find the new interrupt information. 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); // Replace the interrupt infomation for pmu source 4. 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; } //********************************************************************************* // PMInstantiatePowerDomains // // This overrides the vanilla implementation in IOPlatformExpert. It instantiates // a root domain with two children, one for the USB bus (to handle the USB idle // power budget), and one for the expansions slots on the PCI bus (to handle // the idle PCI power budget) //********************************************************************************* void MacRISC4PE::PMInstantiatePowerDomains ( void ) { IOPMUSBMacRISC4 * usbMacRISC4; const OSSymbol *desc = OSSymbol::withCString("powertreedesc"); // Move our power tree description from our driver (where it's a property in the driver) // to our provider 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); // No need to keep original around removeProperty(desc); root = IOPMrootDomain::construct(); root->attach(this); root->start(this); 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; } //********************************************************************************* // PMRegisterDevice // // This overrides the vanilla implementation in IOPlatformExpert. We try to // put a device into the right position within the power domain hierarchy. //********************************************************************************* extern const IORegistryPlane * gIOPowerPlane; void MacRISC4PE::PMRegisterDevice(IOService * theNub, IOService * theDevice) { bool nodeFound = false; IOReturn err = -1; OSData * propertyPtr = 0; const char * theProperty; // Starts the protected area, we are trying to protect numInstancesRegistered if (pmmutex != NULL) IOLockLock(pmmutex); // reset our tracking variables before we check the XML-derived tree multipleParentKeyValue = NULL; numInstancesRegistered = 0; // try to find a home for this registrant in our XML-derived tree nodeFound = CheckSubTree (thePowerTree, theNub, theDevice, NULL); if (0 == numInstancesRegistered) { // make sure the provider is within the Power Plane...if not, // back up the hierarchy until we find a grandfather or great // grandfather, etc., that is in the Power Plane. while( theNub && (!theNub->inPlane(gIOPowerPlane))) theNub = theNub->getProvider(); } // Ends the protected area, we are trying to protect numInstancesRegistered if (pmmutex != NULL) IOLockUnlock(pmmutex); // try to register with the given (or reassigned in the case above) provider. if ( NULL != theNub ) err = theNub->addPowerChild (theDevice); // failing that then register with root (but only if we didn't register in the // XML-derived tree and only if the device we're registering is not the root). if ((err != IOPMNoErr) && (0 == numInstancesRegistered) && (theDevice != root)) { root->addPowerChild (theDevice); } // in addition, if it's in a PCI slot, give it to the Aux Power Supply driver 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; }