extern "C" {
#include <ppc/proc_reg.h>
}
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/pci/IOPCIBridge.h>
#include "GossamerCPU.h"
#include "Gossamer.h"
extern "C" {
unsigned int ml_throttle(unsigned int step);
int kdp_getc(void);
void machine_idle(void);
}
#define super IOCPU
OSDefineMetaClassAndStructors(GossamerCPU, IOCPU);
UInt32 GossamerCPU::restartAddress = 0x100;
IOService *GossamerCPU::findIOInterface(char *name)
{
OSDictionary *dict;
IOService *service;
heathrow = NULL;
dict = serviceMatching(name);
if (dict == NULL) {
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::findIOInterface faild to get a matching dictionary for %s\n", name);
#endif // VERBOSE_LOGS_ON
return NULL;
}
service = waitForService(dict, NULL);
if (service == NULL) {
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::findIOInterface failed to get a matching service for %s\n", name);
#endif// VERBOSE_LOGS_ON
return NULL;
}
return (service);
}
bool GossamerCPU::start(IOService *provider)
{
kern_return_t result;
ml_processor_info_t processor_info;
bool success = super::start(provider);
GossamerPE *gossamerBoard;
if (!success)
return false;
heathrow_sleepState = OSSymbol::withCString("heathrow_sleepState");
heathrow_set_light = OSSymbol::withCString("heathrow_set_light");
cuda_check_any_interrupt = OSSymbol::withCString("cuda_check_any_interrupt");
usb_remote_wakeup = OSSymbol::withCString("usb_remote_wakeup");
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::start start\n");
#endif // VERBOSE_LOGS_ON
gossamerBoard = OSDynamicCast(GossamerPE, getPlatform());
if (gossamerBoard == 0) {
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::start this is not a GossamerPE\n");
#endif // VERBOSE_LOGS_ON
return false;
}
cpuIC = new IOCPUInterruptController;
if (cpuIC == 0)
return false;
if (cpuIC->initCPUInterruptController(1) != kIOReturnSuccess) return false;
cpuIC->attach(this);
cpuIC->registerCPUInterruptController();
processor_info.cpu_id = (cpu_id_t)this;
processor_info.boot_cpu = true;
processor_info.start_paddr = restartAddress;
processor_info.l2cr_value = mfl2cr() & 0x7FFFFFFF; processor_info.supports_nap = false; processor_info.time_base_enable = 0;
result = ml_processor_register(&processor_info, &machProcessor,
&ipi_handler);
if (result == KERN_FAILURE)
return false;
setCPUState(kIOCPUStateUninitalized);
processor_start(machProcessor);
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::start end %d \n", success);
#endif // VERBOSE_LOGS_ON
registerService();
return success;
}
void GossamerCPU::ipiHandler(void *refCon, void *nub, int source)
{
if (ipi_handler)
ipi_handler();
}
void GossamerCPU::initCPU(bool boot)
{
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::initCPU start\n");
#endif // VERBOSE_LOGS_ON
if (grackle != NULL) {
IOPCIAddressSpace grackleSpace;
UInt32 grackleMemConfiguration;
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::initCPU AppleGracklePCI sets the ram in autorefresh off\n");
#endif // VERBOSE_LOGS_ON
grackleSpace.bits = 0x80000000;
grackleMemConfiguration = grackle->configRead32(grackleSpace, 0x70);
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::initCPU AppleGracklePCI current power managment mode :0x%08lx\n", grackleMemConfiguration);
#endif // VERBOSE_LOGS_ON
grackleMemConfiguration &= ~(0x90);
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::initCPU AppleGracklePCI new power managment mode :0x%08lx\n", grackleMemConfiguration);
#endif // VERBOSE_LOGS_ON
grackle->configWrite32(grackleSpace, 0x70, grackleMemConfiguration);
grackle = NULL;
}
else
kprintf("GossamerCPU::initCPU not found AppleGracklePCI\n");
if (heathrow != NULL) {
heathrow->callPlatformFunction(heathrow_sleepState, false, (void *)false, 0, 0, 0);
heathrow = NULL;
}
else
kprintf("GossamerCPU::initCPU not found Heathrow\n");
if(!boot)
saveTimeBase(false);
if (boot)
cpuIC->enableCPUInterrupt(this);
setCPUState(kIOCPUStateRunning);
gossamerPE = OSDynamicCast(GossamerPE, getPlatform());
if (gossamerPE ) {
gossamerPE->setProperty("GossamerCudaSleeping", false);
}
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::initCPU end\n");
#endif VERBOSE_LOGS_ON
}
extern UInt32 ResetHandler;
#ifdef VERBOSE_LOGS_ON
static void
cpu_foo_wake()
{
__asm__ volatile("_gossamer_cpu_wake:");
__asm__ volatile(" ba 0x100");
}
#endif // VERBOSE_LOGS_ON
#define cFlush(addr) __asm__ volatile("dcbf 0, %0" : : "r" (addr))
extern "C" {
void gossamer_cpu_wake(void);
extern void cacheInit(void);
extern void cacheDisable(void);
}
void GossamerCPU::quiesceCPU(void)
{
UInt32 larsCode = (((UInt32)'L') << 24) | (((UInt32)'a') << 16) | (((UInt32)'r') << 8) | (((UInt32)'s') << 0);
UInt32 restartReferencePhi = pmap_extract(kernel_pmap,(vm_address_t)&restartAddress);
ml_set_interrupts_enabled(FALSE);
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU BEFORE 0x%08lx 0x%08lx start\n", 0x00000000, ml_phys_read(0x00000000));
kprintf("GossamerCPU::quiesceCPU BEFORE 0x%08lx 0x%08lx start\n", 0x00000004, ml_phys_read(0x00000004));
ml_phys_write(restartReferencePhi, gossamer_cpu_wake); eieio();
#else
ml_phys_write(restartReferencePhi, 0x100); eieio();
#endif // VERBOSE_LOGS_ON
ml_phys_write(0x00000000, restartReferencePhi);
eieio();
ml_phys_write(0x00000004, larsCode);
eieio();
flush_dcache(restartReferencePhi, 4, true);
flush_dcache(0x00000000, 8, true);
flush_dcache(&ResetHandler, 12, true);
__asm__ volatile("sync");
__asm__ volatile("isync");
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", 0x00000000, ml_phys_read(0x00000000));
kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", ml_phys_read(0x00000000), ml_phys_read(ml_phys_read(0x00000000)));
kprintf("GossamerCPU::quiesceCPU AFTER 0x%08lx 0x%08lx start\n", 0x00000004, ml_phys_read(0x00000004));
#endif
if (pmu != 0)
pmu->callPlatformFunction("sleepNow", false, 0, 0, 0, 0);
else
kprintf("GossamerCPU::quiesceCPU can't find ApplePMU\n");
if (heathrow != NULL) {
heathrow->callPlatformFunction(heathrow_sleepState, false, (void *)true, 0, 0, 0);
}
else
kprintf("GossamerCPU::quiesceCPU not found Heathrow\n");
if (grackle != NULL) {
IOPCIAddressSpace grackleSpace;
UInt32 grackleProcConfiguration, grackleMemConfiguration;
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU AppleGracklePCI sets the ram in autorefresh\n");
grackleSpace.bits = 0x80000000;
grackleProcConfiguration = grackle->configRead32(grackleSpace, 0xA8);
kprintf("GossamerCPU::quiesceCPU AppleGracklePCI current processorinterface conf :0x%08lx\n", grackleProcConfiguration);
#endif // VERBOSE_LOGS_ON
grackleSpace.bits = 0x80000000;
grackleMemConfiguration = grackle->configRead32(grackleSpace, 0x70);
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU AppleGracklePCI current power managment mode :0x%08lx\n", grackleMemConfiguration);
#endif // VERBOSE_LOGS_ON
grackleMemConfiguration |= 0x90;
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU AppleGracklePCI new power managment mode :0x%08lx\n", grackleMemConfiguration);
#endif // VERBOSE_LOGS_ON
grackle->configWrite32(grackleSpace, 0x70, grackleMemConfiguration);
}
else
kprintf("GossamerCPU::quiesceCPU not found AppleGracklePCI\n");
saveTimeBase(true);
cacheInit();
cacheDisable();
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::quiesceCPU calling ml_ppc_sleep\n");
#endif // VERBOSE_LOGS_ON
while(true) {
}
}
const OSSymbol *GossamerCPU::getCPUName(void)
{
return OSSymbol::withCStringNoCopy("Primary0");
}
kern_return_t GossamerCPU::startCPU(vm_offset_t ,
vm_offset_t )
{
return KERN_FAILURE;
}
void GossamerCPU::haltCPU(void)
{
long machine_type;
grackle = NULL;
grackle = OSDynamicCast(AppleGracklePCI, findIOInterface("AppleGracklePCI"));
if (grackle == NULL)
kprintf("GossamerCPU::haltCPU missing grackle\n");
pci2pciBridge = NULL;
heathrow = OSDynamicCast(IOService, findIOInterface("Heathrow"));
#ifdef VERBOSE_LOGS_ON
kprintf("GossamerCPU::haltCPU Here!\n");
#endif // VERBOSE_LOGS_ON
gossamerPE = OSDynamicCast(GossamerPE, getPlatform());
if (gossamerPE == 0 )
{
processor_exit(machProcessor);
return;
}
machine_type = gossamerPE->getMachineType();
if ((machine_type != kGossamerType101) && (machine_type != kGossamerTypeWallstreet))
{
mach_timespec_t t;
IOService *cudaDriver;
IOService *usbOHCIDriver;
bool anyint = false;
t.tv_sec = 1;
t.tv_nsec = 0;
cudaDriver = waitForService(serviceMatching("AppleCuda"), &t);
usbOHCIDriver = waitForService(serviceMatching("AppleUSBOHCI"), &t);
if ((heathrow != NULL) && (machine_type == kGossamerTypeYosemite))
{
heathrow->callPlatformFunction(heathrow_set_light, false, (void *)false, 0, 0, 0);
}
gossamerPE->setProperty("GossamerCudaSleeping", true);
ml_throttle(254);
while (true) {
machine_idle(); if (cudaDriver != NULL)
{
anyint = false;
cudaDriver->callPlatformFunction(cuda_check_any_interrupt, false, (void *)&anyint, 0, 0, 0);
if (anyint)
{
break;
}
}
if (usbOHCIDriver != NULL)
{
anyint = false;
usbOHCIDriver->callPlatformFunction(usb_remote_wakeup, false, (void *)&anyint, 0, 0, 0);
if (anyint)
{
break;
}
}
IOSleep(5); }
ml_throttle(0);
gossamerPE->setProperty("GossamerCudaSleeping", false);
if ((heathrow != NULL) && (machine_type == kGossamerTypeYosemite))
{
heathrow->callPlatformFunction(heathrow_set_light, false, (void *)true, 0, 0, 0);
}
}
else
{
pmu = OSDynamicCast(IOService, findIOInterface("ApplePMU"));
processor_exit(machProcessor);
}
}
void GossamerCPU::saveTimeBase(bool save)
{
if(save) { do {
tbHigh = mftbu();
tbLow = mftb();
tbHigh2 = mftbu();
} while (tbHigh != tbHigh2);
} else { mttb(0);
mttbu(tbHigh);
mttb(tbLow);
}
}