#include <sys/cdefs.h>
__BEGIN_DECLS
#include <ppc/proc_reg.h>
#include <ppc/machine_routines.h>
__END_DECLS
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOCPU.h>
#include <IOKit/pci/IOPCIBridge.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include "MacRISC2CPU.h"
#define kMacRISC_GPIO_DIRECTION_BIT 2
#ifndef kIOHibernateStateKey
#define kIOHibernateStateKey "IOHibernateState"
#endif
#define super IOCPU
OSDefineMetaClassAndStructors(MacRISC2CPU, IOCPU);
static IOCPUInterruptController *gCPUIC;
static UInt32 *gPHibernateState;
bool MacRISC2CPU::start(IOService *provider)
{
kern_return_t result;
IORegistryEntry *cpusRegEntry, *uniNRegEntry, *mpicRegEntry, *devicetreeRegEntry;
OSIterator *cpusIterator;
OSData *tmpData;
IOService *service;
const OSSymbol *interruptControllerName;
OSData *interruptData;
OSArray *tmpArray;
UInt32 maxCPUs, uniNVersion, physCPU;
ml_processor_info_t processor_info;
#if enableUserClientInterface
DFScontMode = 0;
fWorkLoop = 0;
DFS_Status = false;
GPU_Status = kGPUHigh;
vStepped = false;
#endif
mpic_getProvider = OSSymbol::withCString("mpic_getProvider");
mpic_getIPIVector= OSSymbol::withCString("mpic_getIPIVector");
mpic_setCurrentTaskPriority = OSSymbol::withCString("mpic_setCurrentTaskPriority");
mpic_setUpForSleep = OSSymbol::withCString("mpic_setUpForSleep");
mpic_dispatchIPI = OSSymbol::withCString("mpic_dispatchIPI");
keyLargo_restoreRegisterState = OSSymbol::withCString("keyLargo_restoreRegisterState");
keyLargo_syncTimeBase = OSSymbol::withCString("keyLargo_syncTimeBase");
keyLargo_saveRegisterState = OSSymbol::withCString("keyLargo_saveRegisterState");
keyLargo_turnOffIO = OSSymbol::withCString("keyLargo_turnOffIO");
keyLargo_writeRegUInt8 = OSSymbol::withCString("keyLargo_writeRegUInt8");
keyLargo_getHostKeyLargo = OSSymbol::withCString("keyLargo_getHostKeyLargo");
keyLargo_setPowerSupply = OSSymbol::withCString("setPowerSupply");
uniN_setPowerState = OSSymbol::withCString(kUniNSetPowerState);
uniN_setAACKDelay = OSSymbol::withCString(kUniNSetAACKDelay);
pmu_cpuReset = OSSymbol::withCString("cpuReset");
ati_prepareDMATransaction = OSSymbol::withCString(kIOFBPrepareDMAValueKey);
ati_performDMATransaction = OSSymbol::withCString(kIOFBPerformDMAValueKey);
macRISC2PE = OSDynamicCast(MacRISC2PE, getPlatform());
if (macRISC2PE == 0) return false;
if (!super::start(provider)) return false;
uniNRegEntry = fromPath("/uni-n", gIODTPlane);
if (uniNRegEntry == 0) return false;
tmpData = OSDynamicCast(OSData, uniNRegEntry->getProperty("device-rev"));
if (tmpData == 0) return false;
uniNVersion = *(long *)tmpData->getBytesNoCopy();
bootCPU = false;
tmpData = OSDynamicCast(OSData, provider->getProperty("state"));
if (tmpData == 0) return false;
if (!strcmp((char *)tmpData->getBytesNoCopy(), "running")) bootCPU = true;
numCPUs = 0;
cpusRegEntry = fromPath("/cpus", gIODTPlane);
if (cpusRegEntry == 0) return false;
cpusIterator = cpusRegEntry->getChildIterator(gIODTPlane);
while (cpusIterator->getNextObject()) numCPUs++;
cpusIterator->release();
if ((numCPUs > 1) && !bootCPU)
(void) waitForService (resourceMatching ("BootCPU"));
if (uniNVersion < kUniNVersion107) numCPUs = 1;
if (PE_parse_boot_arg("cpus", &maxCPUs))
{
if (numCPUs > maxCPUs) numCPUs = maxCPUs;
}
ignoreSpeedChange = false;
doSleep = false;
topLevelPCIBridgeCount = 0;
flushOnLock = false;
cpusRegEntry = fromPath("/cpus/@0", gIODTPlane);
if (cpusRegEntry == 0) return false;
if (cpusRegEntry->getProperty("flush-on-lock") != 0) flushOnLock = true;
if (numCPUs != 1) flushOnLock = true;
devicetreeRegEntry = fromPath("/", gIODTPlane);
tmpData = OSDynamicCast(OSData, devicetreeRegEntry->getProperty("model"));
if (tmpData == 0) return false;
#if 0
if(!strcmp((char *)tmpData->getBytesNoCopy(), "PowerMac3,5"))
flushOnLock = true;
#endif
tmpData = OSDynamicCast(OSData, provider->getProperty("reg"));
if (tmpData == 0) return false;
physCPU = *(long *)tmpData->getBytesNoCopy();
setCPUNumber(physCPU);
tmpData = OSDynamicCast(OSData, provider->getProperty("soft-reset"));
if (tmpData == 0)
{
if (physCPU == 0)
soft_reset_offset = 0x5B;
else
soft_reset_offset = 0x5C;
}
else
soft_reset_offset = *(long *)tmpData->getBytesNoCopy();
tmpData = OSDynamicCast(OSData, provider->getProperty("timebase-enable"));
if (tmpData == 0)
timebase_enable_offset = 0x73;
else
timebase_enable_offset = *(long *)tmpData->getBytesNoCopy();
resetOnWake = (provider->getProperty ("reset-on-wake") != NULL);
if (resetOnWake) {
vm_address_t reserveMem;
reserveMem = (vm_address_t)IOMallocAligned (PAGE_SIZE, PAGE_SIZE); if (reserveMem) {
reserveMemDesc = IOMemoryDescriptor::withAddress (reserveMem, PAGE_SIZE, kIODirectionNone, NULL);
if (reserveMemDesc) {
reserveMemPhys = reserveMemDesc->getPhysicalAddress();
}
}
}
needVSetting = (provider->getProperty( "vmin" ) != 0);
needAACKDelay = false;
if (bootCPU)
{
gCPUIC = new IOCPUInterruptController;
if (gCPUIC == 0) return false;
if (gCPUIC->initCPUInterruptController(numCPUs) != kIOReturnSuccess)
return false;
gCPUIC->attach(this);
gCPUIC->registerCPUInterruptController();
}
tmpData = OSDynamicCast(OSData, provider->getProperty("l2cr"));
if (tmpData != 0)
{
l2crValue = *(long *)tmpData->getBytesNoCopy() & 0x7FFFFFFF;
}
else
{
l2crValue = mfl2cr() & 0x7FFFFFFF;
}
keyLargo = waitForService(serviceMatching("KeyLargo"));
if (keyLargo == 0) return false;
keyLargo->callPlatformFunction (keyLargo_getHostKeyLargo, false, &keyLargo, 0, 0, 0);
if (keyLargo == 0)
{
kprintf ("MacRISC2CPU::start - getHostKeyLargo returned nil\n");
return false;
}
mpic = waitForService(serviceMatching("AppleMPICInterruptController"));
if (mpic == 0) return false;
mpic->callPlatformFunction(mpic_getProvider, false, (void *)&mpicRegEntry, 0, 0, 0);
interruptControllerName = IODTInterruptControllerName(mpicRegEntry);
mpic->callPlatformFunction(mpic_getIPIVector, false, (void *)&physCPU, (void *)&interruptData, 0, 0);
if ((interruptControllerName == 0) || (interruptData == 0)) return false;
tmpArray = OSArray::withCapacity(1);
tmpArray->setObject(interruptControllerName);
cpuNub->setProperty(gIOInterruptControllersKey, tmpArray);
tmpArray->release();
tmpArray = OSArray::withCapacity(1);
tmpArray->setObject(interruptData);
cpuNub->setProperty(gIOInterruptSpecifiersKey, tmpArray);
tmpArray->release();
setCPUState(kIOCPUStateUninitalized);
if (bootCPU)
publishResource ("BootCPU", this);
if (physCPU < numCPUs)
{
processor_info.cpu_id = (cpu_id_t)this;
processor_info.boot_cpu = bootCPU;
processor_info.start_paddr = 0x0100;
processor_info.l2cr_value = l2crValue;
processor_info.supports_nap = !flushOnLock;
processor_info.time_base_enable =
OSMemberFunctionCast(time_base_enable_t, this, &MacRISC2CPU::enableCPUTimeBase);
result = ml_processor_register(&processor_info, &machProcessor, &ipi_handler);
if (result == KERN_FAILURE) return false;
processor_start(machProcessor);
}
service = waitForService(serviceMatching("IOPMrootDomain"));
pmRootDomain = OSDynamicCast(IOPMrootDomain, service);
if (pmRootDomain != 0)
{
kprintf("Register MacRISC2CPU %ld to acknowledge power changes\n", getCPUNumber());
pmRootDomain->registerInterestedDriver(this);
PMinit();
provider->joinPMtree(this);
}
pmu = waitForService(serviceMatching("ApplePMU"));
uniN = waitForService(serviceMatching("AppleUniN"));
if ((pmu == 0) || (uniN == 0)) return false;
if (macRISC2PE->hasPMon) {
service = waitForService(resourceMatching("IOPlatformMonitor"));
ioPMon = OSDynamicCast (IOPlatformMonitor, service->getProperty("IOPlatformMonitor"));
if (!ioPMon)
return false;
ioPMonDict = OSDictionary::withCapacity(2);
if (!ioPMonDict) {
ioPMon = NULL;
} else {
ioPMonDict->setObject (kIOPMonTypeKey, OSSymbol::withCString (kIOPMonTypeCPUCon));
ioPMonDict->setObject (kIOPMonCPUIDKey, OSNumber::withNumber ((long long)getCPUNumber(), 32));
if (messageClient (kIOPMonMessageRegister, ioPMon, (void *)ioPMonDict) != kIOReturnSuccess) {
IOLog ("MacRISC2CPU::start - failed to register cpu with IOPlatformMonitor\n");
ioPMonDict->release();
ioPMon = NULL;
}
}
}
if (macRISC2PE->hasPPlugin) {
IOService *ioPPlugin;
OSDictionary *ioPPluginDict;
service = waitForService(resourceMatching("IOPlatformPlugin"));
ioPPlugin = OSDynamicCast (IOService, service->getProperty("IOPlatformPlugin"));
if (!ioPPlugin)
return false;
ioPPluginDict = OSDictionary::withCapacity(2);
if (ioPPluginDict) {
ioPPluginDict->setObject ("cpu-id", OSNumber::withNumber ((long long)getCPUNumber(), 32));
if (messageClient (kIOPMonMessageRegister, ioPPlugin, (void *)ioPPluginDict) != kIOReturnSuccess) {
IOLog ("MacRISC2CPU::start - failed to register cpu with IOPlatformPlugin\n");
}
ioPPluginDict->release(); }
}
#if enableUserClientInterface
fWorkLoop = getWorkLoop();
if(!fWorkLoop)
{
IOLog("MacRISC2CPU::start ERROR: failed to find a fWorkLoop\n");
}
if(!initTimers())
{
IOLog("MacRISC2CPU::start ERROR: failed to init the timers\n");
}
#endif
registerService();
return true;
}
IOReturn MacRISC2CPU::powerStateWillChangeTo ( IOPMPowerFlags theFlags, unsigned long, IOService*)
{
if (!gPHibernateState) {
OSData * data = OSDynamicCast(OSData, getPMRootDomain()->getProperty(kIOHibernateStateKey));
if (data)
gPHibernateState = (UInt32 *) data->getBytesNoCopy();
}
if ( ! (theFlags & IOPMPowerOn) ) {
kprintf("MacRISC2CPU %ld powerStateWillChangeTo to acknowledge power changes (DOWN) we set napping %d\n", getCPUNumber(), false);
rememberNap = ml_enable_nap(getCPUNumber(), false);
if (macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange &&
!(macRISC2PE->processorSpeedChangeFlags & kProcessorFast)) {
setAggressiveness (kPMSetProcessorSpeed, 0); macRISC2PE->processorSpeedChangeFlags &= ~kProcessorFast; }
if(macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange)
{
ignoreSpeedChange = true;
}
} else {
if(macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange)
{
ignoreSpeedChange = false;
}
kprintf("MacRISC2CPU %ld powerStateWillChangeTo to acknowledge power changes (UP) we set napping %d\n", getCPUNumber(), rememberNap);
ml_enable_nap(getCPUNumber(), rememberNap);
if (!ioPMon && (macRISC2PE->processorSpeedChangeFlags & kEnvironmentalSpeedChange)) {
if (macRISC2PE->processorSpeedChangeFlags & kProcessorFast) {
macRISC2PE->processorSpeedChangeFlags &= ~kProcessorFast; setAggressiveness (kPMSetProcessorSpeed, 0); } else
doSleep = true; }
if (macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange &&
!(macRISC2PE->processorSpeedChangeFlags & kProcessorFast)) {
macRISC2PE->processorSpeedChangeFlags |= kProcessorFast; setAggressiveness (kPMSetProcessorSpeed, 1); }
}
return IOPMAckImplied;
}
IOReturn MacRISC2CPU::setAggressiveness(UInt32 selector, UInt32 newLevel)
{
bool doChange = false;
IOReturn result;
if((selector == kPMSetProcessorSpeed) && (macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange) && (ignoreSpeedChange == true))
{
return IOPMNoErr;
}
result = super::setAggressiveness(selector, newLevel);
if (macRISC2PE->hasPPlugin) {
return IOPMNoErr;
}
newLevel &= 0x7FFFFFFF; if ((selector == kPMSetProcessorSpeed) && (macRISC2PE->processorSpeedChangeFlags != kNoSpeedChange))
{
if (ioPMon) {
if (newLevel < 2)
return result;
newLevel -= 2;
doChange = true; }
if (doSleep) {
IOSleep (1000);
doSleep = false;
}
if (macRISC2PE->processorSpeedChangeFlags & kDisableL2SpeedChange) {
if (!(macRISC2PE->processorSpeedChangeFlags & kClamshellClosedSpeedChange)) {
if (!newLevel) {
if (!(macRISC2PE->processorSpeedChangeFlags & kL2CacheEnabled)) {
ml_enable_cache_level(2, !newLevel);
macRISC2PE->processorSpeedChangeFlags |= kL2CacheEnabled;
}
} else if (macRISC2PE->processorSpeedChangeFlags & kL2CacheEnabled) {
ml_enable_cache_level(2, !newLevel);
macRISC2PE->processorSpeedChangeFlags &= ~kL2CacheEnabled;
}
}
}
if (macRISC2PE->processorSpeedChangeFlags & kDisableL3SpeedChange) {
if (!(macRISC2PE->processorSpeedChangeFlags & kClamshellClosedSpeedChange)) {
if (!newLevel) {
if (!(macRISC2PE->processorSpeedChangeFlags & kL3CacheEnabled)) {
ml_enable_cache_level(3, !newLevel);
macRISC2PE->processorSpeedChangeFlags |= kL3CacheEnabled;
}
}
else if (macRISC2PE->processorSpeedChangeFlags & kL3CacheEnabled)
{
ml_enable_cache_level(3, !newLevel);
macRISC2PE->processorSpeedChangeFlags &= ~kL3CacheEnabled;
}
}
}
if (!newLevel)
{
if (!(macRISC2PE->processorSpeedChangeFlags & kProcessorFast))
{
doChange = true;
macRISC2PE->processorSpeedChangeFlags |= kProcessorFast;
}
}
else if (macRISC2PE->processorSpeedChangeFlags & kProcessorFast)
{
doChange = true;
macRISC2PE->processorSpeedChangeFlags &= ~kProcessorFast;
}
if (macRISC2PE->processorSpeedChangeFlags & kPMUBasedSpeedChange)
{
if (doChange)
performPMUSpeedChange (newLevel);
}
if ((macRISC2PE->processorSpeedChangeFlags & kProcessorBasedSpeedChange) && doChange && ! (macRISC2PE->processorSpeedChangeFlags & kBusSlewBasedSpeedChange))
{
IOReturn cpfResult = kIOReturnSuccess;
if (newLevel == 0)
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)1, (void *)0, (void *)0, (void *)0);
if (cpfResult == kIOReturnSuccess)
{
if (needVSetting && (newLevel == 0))
ml_set_processor_voltage(0);
if (needAACKDelay && (newLevel == 1))
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)1, (void *)0, (void *)0, (void *)0);
ml_set_processor_speed(newLevel ? 1 : 0);
if (needAACKDelay & (newLevel == 0))
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)0, (void *)0, (void *)0, (void *)0);
if (needVSetting && (newLevel != 0))
ml_set_processor_voltage(1);
if (newLevel != 0)
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)0, (void *)0, (void *)0, (void *)0);
}
}
}
return result;
}
void MacRISC2CPU::performPMUSpeedChange (UInt32 newLevel)
{
bool tempRememberNap;
currentProcessorSpeed = newLevel;
tempRememberNap = ml_enable_nap(getCPUNumber(), false);
processorSpeedChange = true;
pmRootDomain->receivePowerNotification(kIOPMProcessorSpeedChange);
processorSpeedChange = false;
ml_enable_nap(getCPUNumber(), tempRememberNap);
return;
}
void MacRISC2CPU::initCPU(bool boot)
{
IOPCIBridge *pciDriver;
UInt32 i;
if (!boot && bootCPU) {
uniN->callPlatformFunction (uniN_setPowerState, false, (void *)kUniNNormal,
(void *)0, (void *)0, (void *)0);
if (!processorSpeedChange) {
for (i = 0; i < topLevelPCIBridgeCount; i++)
if (pciDriver = topLevelPCIBridges[i])
pciDriver->setDevicePowerState (NULL, 3);
if (resetOnWake && (!gPHibernateState || !*gPHibernateState)) {
bool doAGPRecovery;
IOReturn result;
doAGPRecovery = false;
if (macRISC2PE->atiDriver) {
macRISC2PE->atiDriver->restoreDeviceState();
if (macRISC2PE->gpuSensor) {
result = macRISC2PE->gpuSensor->callPlatformFunction (ati_prepareDMATransaction, false, (void *)reserveMemDesc, 0, 0, 0);
if (result == kIOReturnSuccess) {
if (macRISC2PE->atiDriver && macRISC2PE->agpBridgeDriver) {
macRISC2PE->atiDriver->resetAGP();
macRISC2PE->agpBridgeDriver->configWrite32(macRISC2PE->agpBridgeDriver->getBridgeSpace(), 0x94, 0);
result = macRISC2PE->gpuSensor->callPlatformFunction (ati_performDMATransaction, false, (void *)reserveMemDesc, 0, 0, 0);
macRISC2PE->atiDriver->resetAGP();
if (result == kIOReturnDMAError)
doAGPRecovery = true;
}
}
}
}
if (doAGPRecovery) {
kprintf("MacRISC2CPU::initCPU - AGP recovery required, issuing cpuReset\n");
pmu->callPlatformFunction (pmu_cpuReset, false, 0, 0, 0, 0);
while (1) ;
}
}
keyLargo->callPlatformFunction(keyLargo_restoreRegisterState, false, 0, 0, 0, 0);
if (macRISC2PE->getMachineType() == kMacRISC2TypePowerMac) {
haveSleptMPIC = false;
kprintf("MacRISC2CPU::initCPU %ld -> mpic->setUpForSleep off", getCPUNumber());
mpic->callPlatformFunction(mpic_setUpForSleep, false, (void *)false, (void *)getCPUNumber(), 0, 0);
}
}
}
kprintf("MacRISC2CPU::initCPU %ld Here!\n", getCPUNumber());
if (bootCPU)
keyLargo->callPlatformFunction(keyLargo_syncTimeBase, false, 0, 0, 0, 0);
if (boot)
{
if (gCPUIC)
gCPUIC->enableCPUInterrupt(this);
else
panic ("MacRISC2CPU: gCPUIC uninitialized for CPU %ld\n", getCPUNumber());
cpuNub->registerInterrupt(0, this, OSMemberFunctionCast(IOInterruptAction, this, &MacRISC2CPU::ipiHandler), 0); cpuNub->enableInterrupt(0);
}
long priority = 0;
mpic->callPlatformFunction(mpic_setCurrentTaskPriority, false, (void *)&priority, 0, 0, 0);
setCPUState(kIOCPUStateRunning);
}
void MacRISC2CPU::quiesceCPU(void)
{
if (bootCPU)
{
if (processorSpeedChange) {
pmu->callPlatformFunction("setSpeedNow", false, (void *)currentProcessorSpeed, 0, 0, 0);
} else {
if (!gPHibernateState || !*gPHibernateState)
pmu->callPlatformFunction("sleepNow", false, 0, 0, 0, 0);
if (!haveSleptMPIC && (macRISC2PE->getMachineType() == kMacRISC2TypePowerMac))
{
haveSleptMPIC = true;
kprintf("MacRISC2CPU::quiesceCPU %ld -> mpic->setUpForSleep off", getCPUNumber());
mpic->callPlatformFunction(mpic_setUpForSleep, false, (void *)true, (void *)getCPUNumber(), 0, 0);
}
kprintf("MacRISC2CPU::quiesceCPU %ld -> keyLargo->saveRegisterState()\n", getCPUNumber());
keyLargo->callPlatformFunction(keyLargo_saveRegisterState, false, 0, 0, 0, 0);
if (!gPHibernateState || !*gPHibernateState)
{
kprintf("MacRISC2CPU::quiesceCPU %ld -> keyLargo->turnOffIO\n", getCPUNumber());
keyLargo->callPlatformFunction(keyLargo_turnOffIO, false, (void *)false, 0, 0, 0);
}
}
kprintf("MacRISC2CPU::quiesceCPU %ld -> here\n", getCPUNumber());
ml_phys_write(0x0080, 0x100);
uniN->callPlatformFunction (uniN_setPowerState, false,
(void *)(kUniNSave),
(void *)0, (void *)0, (void *)0);
if (processorSpeedChange || (!gPHibernateState || !*gPHibernateState)) {
uniN->callPlatformFunction (uniN_setPowerState, false,
(void *)(processorSpeedChange ? kUniNIdle2 : kUniNSleep),
(void *)0, (void *)0, (void *)0);
}
}
ml_ppc_sleep();
}
kern_return_t MacRISC2CPU::startCPU(vm_offset_t , vm_offset_t )
{
long gpioOffset = soft_reset_offset;
unsigned long strobe_value;
strobe_value = ( 1 << kMacRISC_GPIO_DIRECTION_BIT );
keyLargo->callPlatformFunction(keyLargo_writeRegUInt8, false,
(void *)&gpioOffset, (void *)strobe_value, 0, 0);
strobe_value = ( 0 << kMacRISC_GPIO_DIRECTION_BIT );
keyLargo->callPlatformFunction(keyLargo_writeRegUInt8, false,
(void *)&gpioOffset, (void *)strobe_value, 0, 0);
return KERN_SUCCESS;
}
void MacRISC2CPU::haltCPU(void)
{
OSIterator *childIterator;
IORegistryEntry *childEntry, *childDriver;
IOPCIBridge *pciDriver;
OSData *deviceTypeString;
UInt32 i;
setCPUState(kIOCPUStateStopped);
if (bootCPU)
{
uniN->callPlatformFunction ("setupUATAforSleep", false, (void *)0, (void *)0, (void *)0, (void *)0);
if (!topLevelPCIBridgeCount) {
if ((childIterator = macRISC2PE->getChildIterator (gIOServicePlane)) != NULL) {
while ((childEntry = (IORegistryEntry *)(childIterator->getNextObject ())) != NULL) {
deviceTypeString = OSDynamicCast( OSData, childEntry->getProperty( "device_type" ));
if (deviceTypeString) {
if (!strcmp((const char *)deviceTypeString->getBytesNoCopy(), "pci")) {
childDriver = childEntry->copyChildEntry(gIOServicePlane);
if (childDriver) {
pciDriver = OSDynamicCast( IOPCIBridge, childDriver );
if (pciDriver)
if (topLevelPCIBridgeCount < kMaxPCIBridges)
topLevelPCIBridges[topLevelPCIBridgeCount++] = pciDriver;
else
kprintf ("MacRISC2CPU::haltCPU - warning, more than %d PCI bridges - cannot save/restore them all\n", kMaxPCIBridges);
childDriver->release();
}
}
}
}
childIterator->release();
}
}
for (i = 0; i < topLevelPCIBridgeCount; i++)
if (pciDriver = topLevelPCIBridges[i]) {
pciDriver->setDevicePowerState (NULL, 2);
}
}
kprintf("MacRISC2CPU::haltCPU %ld Here!\n", getCPUNumber());
processor_exit(machProcessor);
}
void MacRISC2CPU::signalCPU(IOCPU *target)
{
UInt32 physCPU = getCPUNumber();
MacRISC2CPU *targetCPU = OSDynamicCast(MacRISC2CPU, target);
if (targetCPU == 0) return;
mpic->callPlatformFunction(mpic_dispatchIPI, false, (void *)&physCPU, (void *)(1 << targetCPU->getCPUNumber()), 0, 0);
}
void MacRISC2CPU::enableCPUTimeBase(bool enable)
{
long gpioOffset = timebase_enable_offset;
unsigned long value;
#if 0
if ( enable )
{
keyLargo->callPlatformFunction(keyLargo_safeReadRegUInt8, false, (void *)&gpioOffset, (void *)&value,
(void *)0, (void *)0);
value = ( 0 << kMacRISC_GPIO_DIRECTION_BIT ); keyLargo->callPlatformFunction(keyLargo_writeRegUInt8, false, (void *)&gpioOffset, (void *)value,
(void *)0, (void *)0);
}
else {
keyLargo->callPlatformFunction(keyLargo_safeReadRegUInt8, false,
(void *)&gpioOffset, (void *)&value, (void *)0, (void *)0);
value &= ~ 0x01; keyLargo->callPlatformFunction(keyLargo_writeRegUInt8, false, (void *)&gpioOffset, (void *)value,
(void *)0, (void *)0);
value |= ( 1 << kMacRISC_GPIO_DIRECTION_BIT ); keyLargo->callPlatformFunction(keyLargo_writeRegUInt8, false, (void *)&gpioOffset, (void *)value,
(void *)0, (void *)0);
sync();
}
#endif
value = ( enable )? ( 0 << kMacRISC_GPIO_DIRECTION_BIT ) : ( 1 << kMacRISC_GPIO_DIRECTION_BIT ); keyLargo->callPlatformFunction( keyLargo_writeRegUInt8, false,
(void *)&gpioOffset, (void *)value, (void *)0, (void *)0);
if ( ! enable ) sync();
}
void MacRISC2CPU::ipiHandler(void *refCon, void *nub, int source)
{
if (ipi_handler) ipi_handler();
}
const OSSymbol *MacRISC2CPU::getCPUName(void)
{
char tmpStr[16];
snprintf(tmpStr, sizeof(tmpStr), "Primary%ld", getCPUNumber());
return OSSymbol::withCString(tmpStr);
}
#if enableUserClientInterface
IOReturn MacRISC2CPU::vStep(UInt32 newLevel)
{
IOLog("MacRISC2CPU::vStep - START!\n");
if (newLevel)
vStepped = true;
else
vStepped = false;
performPMUSpeedChange (newLevel);
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::vStepCont(UInt32 delayTime)
{
IOLog("MacRISC2CPU::vStepCont - START - delay time = %ld ms\n", delayTime);
vStepTime = delayTime;
fVStepContTimer->setTimeoutMS(vStepTime);
IOLog("MacRISC2CPU::vStepCont - STOP\n");
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::vStepStopCont(void)
{
IOLog("MacRISC2CPU::vStepStopCont START\n");
if(fVStepContTimer)
fVStepContTimer->cancelTimeout();
IOLog("MacRISC2CPU::vStepStopCont STOP\n");
return kIOReturnSuccess;
}
void MacRISC2CPU::vStepContTimerEventOccurred(IOTimerEventSource *sender)
{
if(vStepped == kSteppedLow)
{
vStepped = kSteppedHigh;
performPMUSpeedChange (kSteppedHigh);
fVStepContTimer->setTimeoutMS(vStepTime);
} else
{
vStepped = kSteppedLow;
performPMUSpeedChange (kSteppedHigh); fVStepContTimer->setTimeoutMS(vStepTime);
}
}
void MacRISC2CPU::vStepTimerEventHandler(OSObject *self, IOTimerEventSource *sender)
{
MacRISC2CPU* mr2cpu = (MacRISC2CPU*)self;
mr2cpu->vStepContTimerEventOccurred(sender);
}
IOReturn MacRISC2CPU::DFS(UInt32 newLevel, UInt32 mode)
{
IOReturn cpfResult = kIOReturnSuccess;
IOLog("MacRISC2CPU::DFS - START!\n");
if (newLevel) {
if (mode & kToggleDelayAACK)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)1, (void *)0, (void *)0, (void *)0);
else
if (needAACKDelay)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)1, (void *)0, (void *)0, (void *)0);
DFS_Status = kDFSLow;
if ( !( mode & kDelayAACKOnly)) {
ml_set_processor_speed(newLevel ? 1 : 0);
if (!( mode & kNoVoltage ))
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)0, (void *)0, (void *)0, (void *)0);
}
}
else {
if (!( mode & kNoVoltage ))
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)1, (void *)0, (void *)0, (void *)0);
DFS_Status = kDFSHigh;
if ( !( mode & kDelayAACKOnly))
ml_set_processor_speed(newLevel ? 1 : 0);
if (mode & kToggleDelayAACK)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)0, (void *)0, (void *)0, (void *)0);
else
if (needAACKDelay)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)0, (void *)0, (void *)0, (void *)0);
}
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::DFSCont(UInt32 delayTime, UInt32 mode)
{
IOLog("MacRISC2CPU::DFSCont - START - delay time = %ld ms\n", delayTime);
DFSTime = delayTime;
fDFSContTimer->setTimeoutMS(DFSTime);
DFScontMode = mode;
IOLog("MacRISC2CPU::DFSCont - STOP\n");
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::SetGPUPower(UInt32 GPUPowerLevel)
{
IOLog("MacRISC2CPU::SetGPU - START - GPU Power level = %ld\n", GPUPowerLevel);
pmRootDomain->setAggressiveness (kIOFBLowPowerAggressiveness, GPUPowerLevel);
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::GPUCont(UInt32 delayTime)
{
IOLog("MacRISC2CPU::GPUCont - START - delay time = %ld ms\n", delayTime);
GPUTime = delayTime;
fGPUContTimer->setTimeoutMS(GPUTime);
DFScontMode = 0;
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::DFSStopCont(void)
{
IOLog("MacRISC2CPU::DFSStopCont START\n");
if(fDFSContTimer)
fDFSContTimer->cancelTimeout();
DFScontMode = 0; IOLog("MacRISC2CPU::DFSStopCont STOP\n");
return kIOReturnSuccess;
}
IOReturn MacRISC2CPU::GPUStopCont(void)
{
IOLog("MacRISC2CPU::GPUStopCont START\n");
if(fGPUContTimer)
fGPUContTimer->cancelTimeout();
DFScontMode = 0; IOLog("MacRISC2CPU::GPUStopCont STOP\n");
return kIOReturnSuccess;
}
void MacRISC2CPU::DFSContTimerEventOccurred(IOTimerEventSource *sender)
{
IOReturn cpfResult = kIOReturnSuccess;
if(DFS_Status == kDFSLow)
{
DFS_Status = kDFSHigh;
if ( ! (DFScontMode & kDelayAACKOnly)) {
if ( ! (DFScontMode & kNoVoltage))
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)1, (void *)0, (void *)0, (void *)0);
ml_set_processor_speed(0);
}
if (DFScontMode & kToggleDelayAACK)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)0, (void *)0, (void *)0, (void *)0);
else
if (needAACKDelay)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)0, (void *)0, (void *)0, (void *)0);
fDFSContTimer->setTimeoutMS(DFSTime);
} else
{
DFS_Status = kDFSLow;
if (DFScontMode & kToggleDelayAACK)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)1, (void *)0, (void *)0, (void *)0);
else
if (needAACKDelay)
uniN->callPlatformFunction (uniN_setAACKDelay, false, (void *)1, (void *)0, (void *)0, (void *)0);
if ( ! (DFScontMode & kDelayAACKOnly)) {
ml_set_processor_speed(1);
if ( ! (DFScontMode & kNoVoltage))
cpfResult = keyLargo->callPlatformFunction (keyLargo_setPowerSupply, false,
(void *)0, (void *)0, (void *)0, (void *)0);
}
fDFSContTimer->setTimeoutMS(DFSTime);
}
}
void MacRISC2CPU::GPUContTimerEventOccurred(IOTimerEventSource *sender)
{
if(GPU_Status == kGPULow)
{
IOLog("MacRISC2CPU::GPUContTimerEventOccurred - set to GPU high\n");
GPU_Status = kGPUHigh;
pmRootDomain->setAggressiveness (kIOFBLowPowerAggressiveness, 0);
fGPUContTimer->setTimeoutMS(GPUTime);
} else
{
IOLog("MacRISC2CPU::GPUContTimerEventOccurred - set to GPU low\n");
GPU_Status = kGPULow;
pmRootDomain->setAggressiveness (kIOFBLowPowerAggressiveness, 2);
fGPUContTimer->setTimeoutMS(GPUTime);
}
}
void MacRISC2CPU::DFSTimerEventHandler(OSObject *self, IOTimerEventSource *sender)
{
MacRISC2CPU* mr2cpu = (MacRISC2CPU*)self;
mr2cpu->DFSContTimerEventOccurred(sender);
}
void MacRISC2CPU::GPUTimerEventHandler(OSObject *self, IOTimerEventSource *sender)
{
MacRISC2CPU* mr2cpu = (MacRISC2CPU*)self;
mr2cpu->GPUContTimerEventOccurred(sender);
}
bool MacRISC2CPU::initTimers(void)
{
fDFSContTimer = IOTimerEventSource::timerEventSource(this, DFSTimerEventHandler);
if(!fDFSContTimer) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to create fDFSContTimer\n");
goto MacRISC2CPU_RemoveBothTimers;
}
if(fWorkLoop->addEventSource(fDFSContTimer) != kIOReturnSuccess) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to add fDFSContTimer to fWorkLoop\n");
fDFSContTimer->release();
goto MacRISC2CPU_RemoveBothTimers;
}
fGPUContTimer = IOTimerEventSource::timerEventSource(this, GPUTimerEventHandler);
if(!fGPUContTimer) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to create fGPUContTimer\n");
goto MacRISC2CPU_RemoveBothTimers2;
}
if(fWorkLoop->addEventSource(fGPUContTimer) != kIOReturnSuccess) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to add fGPUContTimer to fWorkLoop\n");
fGPUContTimer->release();
goto MacRISC2CPU_RemoveBothTimers2;
}
fVStepContTimer = IOTimerEventSource::timerEventSource(this, vStepTimerEventHandler);
if(!fVStepContTimer) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to create fVStepContTimer\n");
goto MacRISC2CPU_RemoveBothTimers3;
}
if(fWorkLoop->addEventSource(fVStepContTimer) != kIOReturnSuccess) {
IOLog("MacRISC2CPU::initTimers ERROR: failed to add fVStepContTimer to fWorkLoop\n");
fVStepContTimer->release();
goto MacRISC2CPU_RemoveBothTimers3;
}
return true;
MacRISC2CPU_RemoveBothTimers:
fWorkLoop->removeEventSource(fDFSContTimer);
fDFSContTimer->release();
IOLog("MacRISC2CPU::initTimers STOP EARLY\n");
return false;
MacRISC2CPU_RemoveBothTimers2:
fWorkLoop->removeEventSource(fGPUContTimer);
fGPUContTimer->release();
IOLog("MacRISC2CPU::initTimers STOP EARLY\n");
return false;
MacRISC2CPU_RemoveBothTimers3:
fWorkLoop->removeEventSource(fVStepContTimer);
fVStepContTimer->release();
IOLog("MacRISC2CPU::initTimers STOP EARLY\n");
return false;
}
#endif