#include <ppc/proc_reg.h>
#include <IOKit/IOLib.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IODeviceMemory.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/ppc/IODBDMA.h>
#include "USBKeyLargo.h"
#include "KeyLargo.h"
#define RevertEndianness32(X) ((X & 0x000000FF) << 24) | \
((X & 0x0000FF00) << 16) | \
((X & 0x00FF0000) >> 16) | \
((X & 0xFF000000) >> 24)
#define super AppleMacIO
OSDefineMetaClassAndStructors(KeyLargo, AppleMacIO);
KeyLargo *gHostKeyLargo = NULL;
extern "C" {
extern UInt32 TimeSystemBusKeyLargo ( IOLogicalAddress keyLargoBaseAddr );
}
bool KeyLargo::init(OSDictionary * properties)
{
savedKeyLargState.thisStateIsValid = false;
cardStatus.cardPower = true;
int i;
for (i = 0; i < kNumUSB; i++)
usbBus[i] = NULL;
return super::init(properties);
}
bool KeyLargo::start(IOService *provider)
{
IORegistryEntry *viaPMU;
OSData *tmpData;
UInt32 pmuVersion;
IORegistryEntry *entry;
entry = fromPath("/", gIODTPlane);
tmpData = OSDynamicCast(OSData, entry->getProperty("clock-frequency"));
if (tmpData == 0) return false;
busSpeed = *(unsigned long *)tmpData->getBytesNoCopy();
tmpData = OSDynamicCast(OSData, provider->getProperty("name"));
if (tmpData == 0) return false;
if (tmpData->isEqualTo ("mac-io", strlen ("mac-io")))
gHostKeyLargo = this;
keyLargo_resetUniNEthernetPhy = OSSymbol::withCString("keyLargo_resetUniNEthernetPhy");
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_safeWriteRegUInt8 = OSSymbol::withCString("keyLargo_safeWriteRegUInt8");
keyLargo_safeReadRegUInt8 = OSSymbol::withCString("keyLargo_safeReadRegUInt8");
keyLargo_safeWriteRegUInt32 = OSSymbol::withCString("keyLargo_safeWriteRegUInt32");
keyLargo_safeReadRegUInt32 = OSSymbol::withCString("keyLargo_safeReadRegUInt32");
keyLargo_powerMediaBay = OSSymbol::withCString("powerMediaBay");
keyLargo_getHostKeyLargo = OSSymbol::withCString("keyLargo_getHostKeyLargo");
if (!super::start(provider))
return false;
mutex = IOSimpleLockAlloc();
if (mutex != NULL)
IOSimpleLockInit( mutex );
keyLargoBaseAddress = fMemory->getVirtualAddress();
AdjustBusSpeeds ( );
tmpData = OSDynamicCast(OSData, provider->getProperty("device-id"));
if (tmpData == 0) return false;
keyLargoDeviceId = *(long *)tmpData->getBytesNoCopy();
tmpData = OSDynamicCast(OSData, provider->getProperty("revision-id"));
if (tmpData == 0) return false;
keyLargoVersion = *(long *)tmpData->getBytesNoCopy();
enableCells();
publishBelow(provider);
pmuVersion = 0;
viaPMU = provider->childFromPath("via-pmu", gIODTPlane);
if (viaPMU != 0) {
tmpData = OSDynamicCast(OSData, viaPMU->getProperty("pmu-version"));
if (tmpData != 0) {
pmuVersion = *(UInt32 *)tmpData->getBytesNoCopy();
if (((pmuVersion & 0x000000FF) == 0x0C) &&
(((pmuVersion >> 8) & 0x0000FFFF) >= 0x0000D044)) {
watchDogTimer = KeyLargoWatchDogTimer::withKeyLargo(this);
}
}
}
mediaIsOn = true;
registerService();
initForPM(provider);
int i;
for (i = 0; i < kNumUSB; i++) {
usbBus[i] = new USBKeyLargo;
if (usbBus[i] != NULL) {
if ( usbBus[i]->init() && usbBus[i]->attach(this)) {
usbBus[i]->initForBus(i);
}
else {
usbBus[i]->release();
}
}
}
return true;
}
void KeyLargo::stop(IOService *provider)
{
int i;
for (i = 0; i < kNumUSB; i++) {
if (usbBus[i] != NULL) {
usbBus[i]->release();
}
}
if (mutex != NULL)
IOSimpleLockFree( mutex );
}
long long KeyLargo::syncTimeBase(void)
{
unsigned long cnt;
unsigned long gtLow, gtHigh, gtHigh2;
unsigned long tbLow, tbHigh, tbHigh2;
long long tmp, diffTicks, ratioLow, ratioHigh;
ratioLow = (busSpeed << 32) / (kKeyLargoGTimerFreq * 4);
ratioHigh = ratioLow >> 32;
ratioLow &= 0xFFFFFFFFULL;
do {
tbHigh = mftbu();
tbLow = mftb();
tbHigh2 = mftbu();
} while (tbHigh != tbHigh2);
diffTicks = ((long long)tbHigh << 32) | tbLow;
for (cnt = 0; cnt < 2; cnt++) {
do {
gtHigh = readRegUInt32(kKeyLargoCounterHiOffset);
gtLow = readRegUInt32(kKeyLargoCounterLoOffset);
gtHigh2 = readRegUInt32(kKeyLargoCounterHiOffset);
} while (gtHigh != gtHigh2);
tmp = gtHigh * ratioLow + gtLow * ratioHigh +
((gtLow * ratioLow + 0x080000000ULL) >> 32);
tbHigh = gtHigh * ratioHigh + (tmp >> 32);
tbLow = tmp & 0xFFFFFFFFULL;
mttb(0);
mttbu(tbHigh);
mttb(tbLow);
}
diffTicks = (((long long)tbHigh << 32) | tbLow) - diffTicks;
return diffTicks;
}
void KeyLargo::turnOffKeyLargoIO(bool restart)
{
UInt32 regTemp;
if (!restart) {
kprintf("KeyLargo::turnOffIO( --FALSE-- )\n");
}
if (!restart) {
regTemp = readRegUInt32(kKeyLargoFCR0);
regTemp |= kKeyLargoFCR0SleepBitsSet;
writeRegUInt32(kKeyLargoFCR0, regTemp);
IODelay(1000);
}
regTemp = readRegUInt32(kKeyLargoFCR0);
regTemp |= kKeyLargoFCR0SleepBitsSet;
regTemp &= ~kKeyLargoFCR0SleepBitsClear;
writeRegUInt32(kKeyLargoFCR0, regTemp);
regTemp = readRegUInt32(kKeyLargoMediaBay);
regTemp |= kKeyLargoMB0DevEnable;
writeRegUInt32(kKeyLargoMediaBay, regTemp);
regTemp = readRegUInt32(kKeyLargoFCR1);
regTemp |= kKeyLargoFCR1SleepBitsSet;
regTemp &= ~kKeyLargoFCR1SleepBitsClear;
writeRegUInt32(kKeyLargoFCR1, regTemp);
regTemp = readRegUInt32(kKeyLargoFCR2);
regTemp |= kKeyLargoFCR2SleepBitsSet;
regTemp &= ~kKeyLargoFCR2SleepBitsClear;
writeRegUInt32(kKeyLargoFCR2, regTemp);
regTemp = readRegUInt32(kKeyLargoFCR3);
if (keyLargoVersion >= kKeyLargoVersion2) {
regTemp |= kKeyLargoFCR3ShutdownPLL2X;
if (!restart) {
regTemp |= kKeyLargoFCR3ShutdownPLLTotal;
}
}
if (restart) {
regTemp |= kKeyLargoFCR3RestartBitsSet;
regTemp &= ~kKeyLargoFCR3RestartBitsClear;
} else {
regTemp |= kKeyLargoFCR3SleepBitsSet;
regTemp &= ~kKeyLargoFCR3SleepBitsClear;
}
writeRegUInt32(kKeyLargoFCR3, regTemp);
if (restart) {
regTemp = readRegUInt32(kKeyLargoFCR0);
regTemp &= ~kKeyLargoFCR0USBRefSuspend;
writeRegUInt32(kKeyLargoFCR0, regTemp);
IODelay(1000);
enableCells();
}
if (restart) {
kprintf("KeyLargo::turnOffIO( --TRUE-- )\n");
}
}
void KeyLargo::turnOffPangeaIO(bool restart)
{
UInt32 regTemp;
regTemp = readRegUInt32(kFCR0Offset);
regTemp |= kPangeaFCR0SleepBitsSet;
regTemp &= ~kPangeaFCR0SleepBitsClear;
writeRegUInt32(kFCR0Offset, regTemp);
regTemp = readRegUInt32(kFCR1Offset);
regTemp |= kPangeaFCR1SleepBitsSet;
regTemp &= ~kPangeaFCR1SleepBitsClear;
writeRegUInt32(kFCR1Offset, regTemp);
regTemp = readRegUInt32(kFCR2Offset);
regTemp |= kPangeaFCR2SleepBitsSet;
regTemp &= ~kPangeaFCR2SleepBitsClear;
writeRegUInt32(kFCR2Offset, regTemp);
regTemp = readRegUInt32(kFCR3Offset);
regTemp |= kPangeaFCR3SleepBitsSet;
regTemp &= ~kPangeaFCR3SleepBitsClear;
writeRegUInt32(kFCR3Offset, regTemp);
regTemp = readRegUInt32(kFCR4Offset);
regTemp |= kPangeaFCR4SleepBitsSet;
regTemp &= ~kPangeaFCR4SleepBitsClear;
writeRegUInt32(kFCR4Offset, regTemp);
return;
}
void KeyLargo::powerMediaBay(bool powerOn, UInt8 powerDevice)
{
UInt32 regTemp;
UInt32 whichDevice = powerDevice;
IOLog("KeyLargo::powerMediaBay(%s) 0x%02x\n", (powerOn ? "TRUE" : "FALSE"), powerDevice);
if (mediaIsOn == powerOn) {
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog("KeyLargo::powerMediaBay mbreg = 0x%08lx\n",readRegUInt32(kKeyLargoMediaBay));
#endif
return;
}
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 0 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp &= (~(kKeyLargoMB0DevReset));
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 1 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
if (powerOn) {
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 2 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp &= (~(kKeyLargoMB0DevPower));
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 3 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
IODelay(500);
}
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 4 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp &= (~(kKeyLargoMB0DevEnable));
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 5 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
IODelay(500);
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 6 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp |= (whichDevice << 11);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 7 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
IODelay(500);
if (!powerOn) {
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 8 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp |= kKeyLargoMB0DevPower;
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 9 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
}
else {
regTemp = readRegUInt32(kKeyLargoMediaBay);
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 10 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
regTemp |= kKeyLargoMB0DevReset;
#ifdef LOG_MEDIA_BAY_TRANSACTIONS
IOLog(" 11 KeyLargo::powerMediaBay = 0x%08lx\n",regTemp);
#endif
writeRegUInt32(kKeyLargoMediaBay, regTemp);
IODelay(500);
regTemp = readRegUInt32(kKeyLargoFCR1);
regTemp |= kKeyLargoFCR1EIDE0Reset;
writeRegUInt32(kKeyLargoFCR1, regTemp);
}
IODelay(500);
mediaIsOn = powerOn;
}
void KeyLargo::powerWireless(bool powerOn)
{
if (cardStatus.cardPower == powerOn)
return;
if (powerOn) {
writeRegUInt8(kKeyLargoExtIntGPIOBase + 10, cardStatus.wirelessCardReg[0]);
writeRegUInt8(kKeyLargoExtIntGPIOBase + 13, cardStatus.wirelessCardReg[1]);
writeRegUInt8(kKeyLargoGPIOBase + 13, cardStatus.wirelessCardReg[2]);
writeRegUInt8(kKeyLargoGPIOBase + 14, cardStatus.wirelessCardReg[3]);
writeRegUInt8(kKeyLargoGPIOBase + 15, cardStatus.wirelessCardReg[4]);
}
else {
cardStatus.wirelessCardReg[0] = readRegUInt8(kKeyLargoExtIntGPIOBase + 10);
cardStatus.wirelessCardReg[1] = readRegUInt8(kKeyLargoExtIntGPIOBase + 13);
cardStatus.wirelessCardReg[2] = readRegUInt8(kKeyLargoGPIOBase + 13);
cardStatus.wirelessCardReg[3] = readRegUInt8(kKeyLargoGPIOBase + 14);
cardStatus.wirelessCardReg[4] = readRegUInt8(kKeyLargoGPIOBase + 15);
writeRegUInt8(kKeyLargoExtIntGPIOBase + 10, 0);
writeRegUInt8(kKeyLargoExtIntGPIOBase + 13, 0);
writeRegUInt8(kKeyLargoGPIOBase + 13, 0);
writeRegUInt8(kKeyLargoGPIOBase + 14, 0);
writeRegUInt8(kKeyLargoGPIOBase + 15, 0);
}
cardStatus.cardPower = powerOn;
}
void KeyLargo::enableCells()
{
UInt32 *fcr0Address = (UInt32*)(keyLargoBaseAddress + 0x38); UInt32 *fcr2Address = (UInt32*)(keyLargoBaseAddress + 0x40); unsigned int debugFlags;
UInt32 bitMask;
UInt32 oldValue;
if (!PE_parse_boot_arg("debug", &debugFlags))
debugFlags = 0;
if( debugFlags & 0x18) {
bitMask = (1 << 6); bitMask |= (1 << 4); bitMask |= (1 << 1);
oldValue = *fcr0Address;
eieio();
oldValue |= RevertEndianness32(bitMask);
*fcr0Address = oldValue;
eieio();
}
bitMask = (1 << 17);
oldValue = *fcr2Address;
eieio();
oldValue |= RevertEndianness32(bitMask);
*fcr2Address = oldValue;
eieio();
}
void KeyLargo::saveRegisterState(void)
{
saveKeyLargoState();
saveVIAState();
powerWireless(false);
savedKeyLargState.thisStateIsValid = true;
}
void KeyLargo::restoreRegisterState(void)
{
if (savedKeyLargState.thisStateIsValid) {
restoreKeyLargoState();
restoreVIAState();
powerWireless(true);
}
savedKeyLargState.thisStateIsValid = false;
}
UInt8 KeyLargo::readRegUInt8(unsigned long offset)
{
return *(UInt8 *)(keyLargoBaseAddress + offset);
}
void KeyLargo::writeRegUInt8(unsigned long offset, UInt8 data)
{
*(UInt8 *)(keyLargoBaseAddress + offset) = data;
eieio();
}
void KeyLargo::safeWriteRegUInt8(unsigned long offset, UInt8 mask, UInt8 data)
{
IOInterruptState intState;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
UInt8 currentReg = readRegUInt8(offset);
currentReg = (currentReg & ~mask) | (data & mask);
writeRegUInt8(offset, currentReg);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
}
UInt8 KeyLargo::safeReadRegUInt8(unsigned long offset)
{
IOInterruptState intState;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
UInt8 currentReg = readRegUInt8(offset);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
return (currentReg);
}
UInt32 KeyLargo::readRegUInt32(unsigned long offset)
{
return lwbrx(keyLargoBaseAddress + offset);
}
void KeyLargo::writeRegUInt32(unsigned long offset, UInt32 data)
{
stwbrx(data, keyLargoBaseAddress + offset);
eieio();
}
void KeyLargo::safeWriteRegUInt32(unsigned long offset, UInt32 mask, UInt32 data)
{
IOInterruptState intState;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
UInt32 currentReg = readRegUInt32(offset);
currentReg = (currentReg & ~mask) | (data & mask);
writeRegUInt32(offset, currentReg);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
}
UInt32 KeyLargo::safeReadRegUInt32(unsigned long offset)
{
IOInterruptState intState;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
UInt32 currentReg = readRegUInt32(offset);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
return (currentReg);
}
void KeyLargo::initForPM (IOService *provider)
{
PMinit(); provider->joinPMtree(this);
#define kNumberOfPowerStates 3
static IOPMPowerState ourPowerStates[kNumberOfPowerStates] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, IOPMSoftSleep, IOPMSoftSleep, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
if (pm_vars != NULL)
registerPowerDriver(this, ourPowerStates, kNumberOfPowerStates);
}
IOReturn KeyLargo::setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice)
{
if (powerStateOrdinal >= kNumberOfPowerStates)
return IOPMAckImplied;
if ( powerStateOrdinal == 0 ) {
kprintf("KeyLargo would be powered off here\n");
}
if ( powerStateOrdinal == 1 ) {
kprintf("KeyLargo would be powered on here\n");
}
return IOPMAckImplied;
}
#define MPIC_OFFSET 0x40000
#define VIA_OFFSET 0x16000
void KeyLargo::saveKeyLargoState(void)
{
KeyLargoMPICState* savedKeyLargoMPICState;
KeyLargoGPIOState* savedKeyLargoGPIOState;
KeyLargoConfigRegistersState* savedKeyLargoConfigRegistersState;
KeyLargoDBDMAState* savedKeyLargoDBDMAState;
KeyLargoAudioState* savedKeyLargoAudioState;
KeyLargoI2SState* savedKeyLargoI2SState;
UInt32 channelOffset;
int i;
UInt8* keyLargoBaseAddr = (UInt8*)keyLargoBaseAddress;
UInt8* mpicBaseAddr = (UInt8*)keyLargoBaseAddress + MPIC_OFFSET;
savedKeyLargoGPIOState = &savedKeyLargState.savedGPIOState;
savedKeyLargoGPIOState->gpioLevels[0] = *(UInt32 *)(keyLargoBaseAddr + 0x50);
savedKeyLargoGPIOState->gpioLevels[1] = *(UInt32 *)(keyLargoBaseAddr + 0x54);
for (i = 0; i < 18; i++)
{
savedKeyLargoGPIOState->extIntGPIO[i] = *(UInt8 *)(keyLargoBaseAddr + 0x58 + i);
}
for (i = 0; i < 17; i++)
{
savedKeyLargoGPIOState->gpio[i] = *(UInt8 *)(keyLargoBaseAddr + 0x6A + i);
}
savedKeyLargoAudioState = &savedKeyLargState.savedAudioState;
for (i = 0, channelOffset = 0; i < 25; i++, channelOffset += 0x0010)
{
savedKeyLargoAudioState->audio[i] = *(UInt32 *) (keyLargoBaseAddr + 0x14000 + channelOffset);
}
savedKeyLargoI2SState = &savedKeyLargState.savedI2SState;
for (i = 0, channelOffset = 0; i < 10; i++, channelOffset += 0x0010)
{
savedKeyLargoI2SState->i2s[i] = *(UInt32 *) (keyLargoBaseAddr + 0x10000 + channelOffset);
savedKeyLargoI2SState->i2s[i + 1] = *(UInt32 *) (keyLargoBaseAddr + 0x11000 + channelOffset);
}
savedKeyLargoDBDMAState = &savedKeyLargState.savedDBDMAState;
for (i = 0, channelOffset = 0; i < 13; i++, channelOffset += 0x0100)
{
volatile DBDMAChannelRegisters* currentChannel;
currentChannel = (volatile DBDMAChannelRegisters *) (keyLargoBaseAddr + 0x8000 + channelOffset);
savedKeyLargoDBDMAState->dmaChannel[i].commandPtrLo = IOGetDBDMACommandPtr(currentChannel);
savedKeyLargoDBDMAState->dmaChannel[i].interruptSelect = IOGetDBDMAInterruptSelect(currentChannel);
savedKeyLargoDBDMAState->dmaChannel[i].branchSelect = IOGetDBDMABranchSelect(currentChannel);
savedKeyLargoDBDMAState->dmaChannel[i].waitSelect = IOGetDBDMAWaitSelect(currentChannel);
}
savedKeyLargoConfigRegistersState = &savedKeyLargState.savedConfigRegistersState;
savedKeyLargoConfigRegistersState->mediaBay = *(UInt32 *)(keyLargoBaseAddr + kMediaBayRegOffset);
for (i = 0; i < 5; i++)
{
savedKeyLargoConfigRegistersState->featureControl[i] = ((UInt32 *)(keyLargoBaseAddr + kFCR0Offset))[i];
}
savedKeyLargoMPICState = &savedKeyLargState.savedMPICState;
savedKeyLargoMPICState->mpicIPI[0] = *(UInt32 *)(mpicBaseAddr + MPICIPI0);
savedKeyLargoMPICState->mpicIPI[1] = *(UInt32 *)(mpicBaseAddr + MPICIPI1);
savedKeyLargoMPICState->mpicIPI[2] = *(UInt32 *)(mpicBaseAddr + MPICIPI2);
savedKeyLargoMPICState->mpicIPI[3] = *(UInt32 *)(mpicBaseAddr + MPICIPI3);
savedKeyLargoMPICState->mpicSpuriousVector = *(UInt32 *)(mpicBaseAddr + MPICSpuriousVector);
savedKeyLargoMPICState->mpicTimerFrequencyReporting = *(UInt32 *)(mpicBaseAddr + MPICTimeFreq);
savedKeyLargoMPICState->mpicTimers[0] = *(MPICTimers *)(mpicBaseAddr + MPICTimerBase0);
savedKeyLargoMPICState->mpicTimers[1] = *(MPICTimers *)(mpicBaseAddr + MPICTimerBase1);
savedKeyLargoMPICState->mpicTimers[2] = *(MPICTimers *)(mpicBaseAddr + MPICTimerBase2);
savedKeyLargoMPICState->mpicTimers[3] = *(MPICTimers *)(mpicBaseAddr + MPICTimerBase3);
for (i = 0; i < 64; i++)
{
savedKeyLargoMPICState->mpicInterruptSourceVectorPriority[i] = *(UInt32 *)(mpicBaseAddr + MPICIntSrcVectPriBase + i * MPICIntSrcSize) & (~0x00000040);
savedKeyLargoMPICState->mpicInterruptSourceDestination[i] = *(UInt32 *)(mpicBaseAddr + MPICIntSrcDestBase + i * MPICIntSrcSize);
}
savedKeyLargoMPICState->mpicCurrentTaskPriorities[0] = *(UInt32 *)(mpicBaseAddr + MPICP0CurrTaskPriority);
savedKeyLargoMPICState->mpicCurrentTaskPriorities[1] = *(UInt32 *)(mpicBaseAddr + MPICP1CurrTaskPriority);
savedKeyLargoMPICState->mpicCurrentTaskPriorities[2] = *(UInt32 *)(mpicBaseAddr + MPICP2CurrTaskPriority);
savedKeyLargoMPICState->mpicCurrentTaskPriorities[3] = *(UInt32 *)(mpicBaseAddr + MPICP3CurrTaskPriority);
}
void KeyLargo::restoreKeyLargoState(void)
{
KeyLargoMPICState* savedKeyLargoMPICState;
KeyLargoGPIOState* savedKeyLargoGPIOState;
KeyLargoConfigRegistersState* savedKeyLargoConfigRegistersState;
KeyLargoDBDMAState* savedKeyLargoDBDMAState;
KeyLargoAudioState* savedKeyLargoAudioState;
KeyLargoI2SState* savedKeyLargoI2SState;
UInt32 channelOffset;
int i;
UInt8* keyLargoBaseAddr = (UInt8*)keyLargoBaseAddress;
UInt8* mpicBaseAddr = (UInt8*)keyLargoBaseAddress + MPIC_OFFSET;
savedKeyLargoMPICState = &savedKeyLargState.savedMPICState;
*(UInt32 *)(mpicBaseAddr + MPICIPI0) = savedKeyLargoMPICState->mpicIPI[0];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICIPI1) = savedKeyLargoMPICState->mpicIPI[1];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICIPI2) = savedKeyLargoMPICState->mpicIPI[2];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICIPI3) = savedKeyLargoMPICState->mpicIPI[3];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICSpuriousVector) = savedKeyLargoMPICState->mpicSpuriousVector;
eieio();
*(UInt32 *)(mpicBaseAddr + MPICTimeFreq) = savedKeyLargoMPICState->mpicTimerFrequencyReporting;
eieio();
*(MPICTimers *)(mpicBaseAddr + MPICTimerBase0) = savedKeyLargoMPICState->mpicTimers[0];
eieio();
*(MPICTimers *)(mpicBaseAddr + MPICTimerBase1) = savedKeyLargoMPICState->mpicTimers[1];
eieio();
*(MPICTimers *)(mpicBaseAddr + MPICTimerBase2) = savedKeyLargoMPICState->mpicTimers[2];
eieio();
*(MPICTimers *)(mpicBaseAddr + MPICTimerBase3) = savedKeyLargoMPICState->mpicTimers[3];
eieio();
for (i = 0; i < 64; i++)
{
*(UInt32 *)(mpicBaseAddr + MPICIntSrcVectPriBase + i * MPICIntSrcSize) = savedKeyLargoMPICState->mpicInterruptSourceVectorPriority[i];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICIntSrcDestBase + i * MPICIntSrcSize) = savedKeyLargoMPICState->mpicInterruptSourceDestination[i];
eieio();
}
*(UInt32 *)(mpicBaseAddr + MPICP0CurrTaskPriority) = savedKeyLargoMPICState->mpicCurrentTaskPriorities[0];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICP1CurrTaskPriority) = savedKeyLargoMPICState->mpicCurrentTaskPriorities[1];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICP2CurrTaskPriority) = savedKeyLargoMPICState->mpicCurrentTaskPriorities[2];
eieio();
*(UInt32 *)(mpicBaseAddr + MPICP3CurrTaskPriority) = savedKeyLargoMPICState->mpicCurrentTaskPriorities[3];
eieio();
savedKeyLargoConfigRegistersState = &savedKeyLargState.savedConfigRegistersState;
*(UInt32 *)(keyLargoBaseAddr + kMediaBayRegOffset) = savedKeyLargoConfigRegistersState->mediaBay;
eieio();
for (i = 0; i < 5; i++)
{
((UInt32 *)(keyLargoBaseAddr + kFCR0Offset))[i] = savedKeyLargoConfigRegistersState->featureControl[i];
eieio();
}
IODelay(250);
savedKeyLargoDBDMAState = &savedKeyLargState.savedDBDMAState;
for (i = 0, channelOffset = 0; i < 13; i++, channelOffset += 0x0100)
{
volatile DBDMAChannelRegisters* currentChannel;
currentChannel = (volatile DBDMAChannelRegisters *) (keyLargoBaseAddr + 0x8000 + channelOffset);
IODBDMAReset((IODBDMAChannelRegisters*)currentChannel);
IOSetDBDMACommandPtr(currentChannel, savedKeyLargoDBDMAState->dmaChannel[i].commandPtrLo);
IOSetDBDMAInterruptSelect(currentChannel, savedKeyLargoDBDMAState->dmaChannel[i].interruptSelect);
IOSetDBDMABranchSelect(currentChannel, savedKeyLargoDBDMAState->dmaChannel[i].branchSelect);
IOSetDBDMAWaitSelect(currentChannel, savedKeyLargoDBDMAState->dmaChannel[i].waitSelect);
}
savedKeyLargoAudioState = &savedKeyLargState.savedAudioState;
for (i = 0, channelOffset = 0; i < 25; i++, channelOffset += 0x0010)
{
*(UInt32 *) (keyLargoBaseAddr + 0x14000 + channelOffset) = savedKeyLargoAudioState->audio[i];
eieio();
}
savedKeyLargoI2SState = &savedKeyLargState.savedI2SState;
for (i = 0, channelOffset = 0; i < 10; i++, channelOffset += 0x0010)
{
*(UInt32 *) (keyLargoBaseAddr + 0x10000 + channelOffset) = savedKeyLargoI2SState->i2s[i];
eieio();
*(UInt32 *) (keyLargoBaseAddr + 0x11000 + channelOffset) = savedKeyLargoI2SState->i2s[i + 1];
eieio();
}
savedKeyLargoGPIOState = &savedKeyLargState.savedGPIOState;
*(UInt32 *)(keyLargoBaseAddr + 0x50) = savedKeyLargoGPIOState->gpioLevels[0];
eieio();
*(UInt32 *)(keyLargoBaseAddr + 0x54) = savedKeyLargoGPIOState->gpioLevels[1];
eieio();
for (i = 0; i < 18; i++)
{
*(UInt8 *)(keyLargoBaseAddr + 0x58 + i) = savedKeyLargoGPIOState->extIntGPIO[i];
eieio();
}
for (i = 0; i < 17; i++)
{
*(UInt8 *)(keyLargoBaseAddr + 0x6A + i) = savedKeyLargoGPIOState->gpio[i];
eieio();
}
}
void KeyLargo::saveVIAState(void)
{
UInt8* viaBase = (UInt8*)keyLargoBaseAddress + VIA_OFFSET;
UInt8* savedKeyLargoViaState = savedKeyLargState.savedVIAState;
savedKeyLargoViaState[0] = *(UInt8*)(viaBase + vBufA);
savedKeyLargoViaState[1] = *(UInt8*)(viaBase + vDIRA);
savedKeyLargoViaState[2] = *(UInt8*)(viaBase + vBufB);
savedKeyLargoViaState[3] = *(UInt8*)(viaBase + vDIRB);
savedKeyLargoViaState[4] = *(UInt8*)(viaBase + vPCR);
savedKeyLargoViaState[5] = *(UInt8*)(viaBase + vACR);
savedKeyLargoViaState[6] = *(UInt8*)(viaBase + vIER);
savedKeyLargoViaState[7] = *(UInt8*)(viaBase + vT1C);
savedKeyLargoViaState[8] = *(UInt8*)(viaBase + vT1CH);
}
void KeyLargo::restoreVIAState(void)
{
UInt8* viaBase = (UInt8*)keyLargoBaseAddress + VIA_OFFSET;
UInt8* savedKeyLargoViaState = savedKeyLargState.savedVIAState;
*(UInt8*)(viaBase + vBufA) = savedKeyLargoViaState[0];
eieio();
*(UInt8*)(viaBase + vDIRA) = savedKeyLargoViaState[1];
eieio();
*(UInt8*)(viaBase + vBufB) = savedKeyLargoViaState[2];
eieio();
*(UInt8*)(viaBase + vDIRB) = savedKeyLargoViaState[3];
eieio();
*(UInt8*)(viaBase + vPCR) = savedKeyLargoViaState[4];
eieio();
*(UInt8*)(viaBase + vACR) = savedKeyLargoViaState[5];
eieio();
*(UInt8*)(viaBase + vIER) = savedKeyLargoViaState[6];
eieio();
*(UInt8*)(viaBase + vT1C) = savedKeyLargoViaState[7];
eieio();
*(UInt8*)(viaBase + vT1CH) = savedKeyLargoViaState[8];
eieio();
}
IOReturn KeyLargo::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
if (functionName == keyLargo_resetUniNEthernetPhy)
{
resetUniNEthernetPhy();
return kIOReturnSuccess;
}
if (functionName == keyLargo_restoreRegisterState)
{
restoreRegisterState();
return kIOReturnSuccess;
}
if (functionName == keyLargo_syncTimeBase)
{
syncTimeBase();
return kIOReturnSuccess;
}
if (functionName == keyLargo_saveRegisterState)
{
saveRegisterState();
return kIOReturnSuccess;
}
if (functionName == keyLargo_turnOffIO)
{
if (keyLargoDeviceId == kKeyLargoDeviceId25)
turnOffPangeaIO((bool)param1);
else
turnOffKeyLargoIO((bool)param1);
return kIOReturnSuccess;
}
if (functionName == keyLargo_writeRegUInt8)
{
writeRegUInt8(*(unsigned long *)param1, (UInt8)param2);
return kIOReturnSuccess;
}
if (functionName == keyLargo_safeWriteRegUInt8)
{
safeWriteRegUInt8((unsigned long)param1, (UInt8)param2, (UInt8)param3);
return kIOReturnSuccess;
}
if (functionName == keyLargo_safeReadRegUInt8)
{
UInt8 *returnval = (UInt8 *)param2;
*returnval = safeReadRegUInt8((unsigned long)param1);
return kIOReturnSuccess;
}
if (functionName == keyLargo_safeWriteRegUInt32)
{
safeWriteRegUInt32((unsigned long)param1, (UInt32)param2, (UInt32)param3);
return kIOReturnSuccess;
}
if (functionName == keyLargo_safeReadRegUInt32)
{
UInt32 *returnval = (UInt32 *)param2;
*returnval = safeReadRegUInt32((unsigned long)param1);
return kIOReturnSuccess;
}
if (functionName == keyLargo_powerMediaBay)
{
bool powerOn = (param1 != NULL);
powerMediaBay(powerOn, (UInt8)param2);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("EnableSCC"))
{
EnableSCC((bool)param1, (UInt8)param2, (bool)param3);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("PowerModem"))
{
PowerModem((bool)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("ModemResetLow"))
{
ModemResetLow();
return kIOReturnSuccess;
}
if (functionName->isEqualTo("ModemResetHigh"))
{
ModemResetHigh();
return kIOReturnSuccess;
}
if (functionName == keyLargo_getHostKeyLargo)
{
UInt32 *returnVal = (UInt32 *)param1;
*returnVal = (UInt32) gHostKeyLargo;
return kIOReturnSuccess;
}
return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
}
void KeyLargo::EnableSCC(bool state, UInt8 device, bool type)
{
UInt32 bitsToSet, bitsToClear, currentReg = 0;
IOInterruptState intState;
if (state)
{
bitsToSet = (1 << 6);
if(device == 0) {
bitsToSet |= (1 << 4);
if(type) {
bitsToClear |= (1 << 1); }
else {
bitsToSet |= (1 << 1); }
}
if(device == 1) {
bitsToSet |= (1 << 5);
if(type) {
bitsToSet |= (1 << 17); bitsToSet |= (1 << 16); bitsToSet |= (1 << 15); bitsToClear |= (1 << 14); bitsToClear |= (1 << 13); bitsToClear |= (1 << 12); bitsToSet |= (1 << 10); bitsToClear |= (1 << 9); bitsToClear |= (1 << 8); bitsToClear |= (1 << 0); }
else {
bitsToSet |= (1 << 0); }
}
if ( mutex != NULL ) intState = IOSimpleLockLockDisableInterrupt(mutex);
currentReg = readRegUInt32( (unsigned long)kKeyLargoFCR0);
currentReg |= bitsToSet;
currentReg &= ~bitsToClear;
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
currentReg |= (1 << 3);
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
IODelay(15000);
currentReg &= ~(1 << 3);
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
if(device == 1 && (type)) {
currentReg = (1 << 11);
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
IODelay(15000);
currentReg &= ~(1 << 11);
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
}
if ( mutex != NULL ) IOSimpleLockUnlockEnableInterrupt(mutex, intState);
}
else
{
if(device == 0)
{
bitsToClear |= (1 << 4); }
if(device == 1)
{
bitsToClear |= (1 << 5);
if (type)
{
bitsToClear |= (1 << 17); bitsToClear |= (1 << 16); bitsToClear |= (1 << 15); bitsToClear |= (1 << 14); bitsToClear |= (1 << 13); bitsToClear |= (1 << 12); bitsToClear |= (1 << 10); bitsToClear |= (1 << 9); bitsToClear |= (1 << 8); }
}
if ( mutex != NULL ) intState = IOSimpleLockLockDisableInterrupt(mutex);
currentReg = readRegUInt32( (unsigned long)kKeyLargoFCR0);
currentReg |= bitsToSet;
currentReg &= ~bitsToClear;
writeRegUInt32( (unsigned long)kKeyLargoFCR0, (UInt32)currentReg );
if ( mutex != NULL ) IOSimpleLockUnlockEnableInterrupt(mutex, intState);
}
return;
}
void KeyLargo::PowerModem(bool state)
{
if (keyLargoDeviceId == kKeyLargoDeviceId25)
{
if (state)
{
writeRegUInt8(kKeyLargoGPIOBase + 0x2, 0x4); eieio();
}
else
{
writeRegUInt8(kKeyLargoGPIOBase + 0x2, 0x5); eieio();
}
}
else
{
if (state)
safeWriteRegUInt32( (unsigned long)kKeyLargoFCR2, (UInt32)(1<<25), (UInt32)(0) );
else
safeWriteRegUInt32( (unsigned long)kKeyLargoFCR2, (UInt32)(1<<25), (UInt32)kKeyLargoFCR2AltDataOut );
}
return;
}
void KeyLargo::ModemResetLow()
{
*(UInt8*)(keyLargoBaseAddress + kKeyLargoGPIOBase + 0x3) |= 0x04; eieio();
*(UInt8*)(keyLargoBaseAddress + kKeyLargoGPIOBase + 0x3) &= ~0x01; eieio();
}
void KeyLargo::ModemResetHigh()
{
*(UInt8*)(keyLargoBaseAddress + kKeyLargoGPIOBase + 0x3) |= 0x04; eieio();
*(UInt8*)(keyLargoBaseAddress + kKeyLargoGPIOBase + 0x3) |= 0x01; eieio();
}
void KeyLargo::resetUniNEthernetPhy(void)
{
writeRegUInt8(kKeyLargoGPIOBase + 16, kKeyLargoGPIOOutputEnable);
IOSleep(10);
writeRegUInt8(kKeyLargoGPIOBase + 16,
kKeyLargoGPIOOutputEnable | kKeyLargoGPIOData);
IOSleep(10);
}
#undef super
#define super IOWatchDogTimer
OSDefineMetaClassAndStructors(KeyLargoWatchDogTimer, IOWatchDogTimer);
KeyLargoWatchDogTimer *KeyLargoWatchDogTimer::withKeyLargo(KeyLargo *keyLargo)
{
KeyLargoWatchDogTimer *watchDogTimer = new KeyLargoWatchDogTimer;
if (watchDogTimer == 0) return 0;
while (1) {
if (!watchDogTimer->init()) break;
watchDogTimer->attach(keyLargo);
if (watchDogTimer->start(keyLargo)) return watchDogTimer;
watchDogTimer->detach(keyLargo);
break;
}
return 0;
}
bool KeyLargoWatchDogTimer::start(IOService *provider)
{
keyLargo = OSDynamicCast(KeyLargo, provider);
if (keyLargo == 0) return false;
return super::start(provider);
}
enum {
kKeyLargoWatchDogLow = 0x15030,
kKeyLargoWatchDogHigh = 0x15034,
kKeyLargoCounterLow = 0x15038,
kKeyLargoCounterHigh = 0x1503C,
kKeyLargoWatchDogEnable = 0x15048
};
void KeyLargoWatchDogTimer::setWatchDogTimer(UInt32 timeOut)
{
UInt32 timeLow, timeHigh, timeHigh2, watchDogLow, watchDogHigh;
UInt64 offset, time;
if (timeOut != 0) {
offset = (UInt64)timeOut * kKeyLargoGTimerFreq;
do {
timeHigh = keyLargo->readRegUInt32(kKeyLargoCounterHigh);
timeLow = keyLargo->readRegUInt32(kKeyLargoCounterLow);
timeHigh2 = keyLargo->readRegUInt32(kKeyLargoCounterHigh);
} while (timeHigh != timeHigh2);
time = (((UInt64)timeHigh) << 32) + timeLow;
time += offset;
watchDogLow = time & 0x0FFFFFFFFULL;
watchDogHigh = time >> 32;
keyLargo->writeRegUInt32(kKeyLargoWatchDogLow, watchDogLow);
keyLargo->writeRegUInt32(kKeyLargoWatchDogHigh, watchDogHigh);
}
keyLargo->writeRegUInt32(kKeyLargoWatchDogEnable,
(timeOut != 0) ? 1 : 0);
}
void KeyLargo::AdjustBusSpeeds ( void )
{
IOInterruptState is;
IOSimpleLock *intLock;
UInt32 ticks;
UInt64 systemBusHz, tmp64;
intLock = IOSimpleLockAlloc();
if (intLock) {
IOSimpleLockInit (intLock);
is = IOSimpleLockLockDisableInterrupt(intLock); }
ticks = TimeSystemBusKeyLargo (keyLargoBaseAddress);
if (intLock) {
IOSimpleLockUnlockEnableInterrupt(intLock, is); IOSimpleLockFree (intLock);
}
systemBusHz = 4194300;
systemBusHz *= 18432000;
systemBusHz /= ticks;
#if 0
kprintf ("KeyLargo::AdjustBusSpeeds - ticks = %ld, new systemBusHz = %ld, old systemBusHz = %ld\n", ticks,
(UInt32)(systemBusHz & 0xFFFFFFFF), (UInt32)(gPEClockFrequencyInfo.bus_clock_rate_hz & 0xFFFFFFFF));
kprintf ("old clock frequency values:\n");
kprintf (" bus_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_hz);
kprintf (" cpu_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.cpu_clock_rate_hz);
kprintf (" dec_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.dec_clock_rate_hz);
kprintf (" bus_clock_rate_num: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_num);
kprintf (" bus_clock_rate_den: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_den);
kprintf (" bus_to_cpu_rate_num: %ld\n", gPEClockFrequencyInfo.bus_to_cpu_rate_num);
kprintf (" bus_to_cpu_rate_den: %ld\n", gPEClockFrequencyInfo.bus_to_cpu_rate_den);
kprintf (" bus_to_dec_rate_num: %ld\n", gPEClockFrequencyInfo.bus_to_dec_rate_num);
kprintf (" bus_to_dec_rate_den: %ld\n", gPEClockFrequencyInfo.bus_to_dec_rate_den);
#endif
tmp64 = systemBusHz;
tmp64 /= gPEClockFrequencyInfo.bus_clock_rate_den;
gPEClockFrequencyInfo.bus_clock_rate_num = (UInt32) (tmp64 & 0xFFFFFFFF);
gPEClockFrequencyInfo.bus_clock_rate_hz = (UInt32) (systemBusHz & 0xFFFFFFFF);
gPEClockFrequencyInfo.dec_clock_rate_hz = (UInt32) ((systemBusHz & 0xFFFFFFFF) / 4);
#if 0
kprintf ("new clock frequency values:\n");
kprintf (" bus_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_hz);
kprintf (" cpu_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.cpu_clock_rate_hz);
kprintf (" dec_clock_rate_hz: %ld\n", gPEClockFrequencyInfo.dec_clock_rate_hz);
kprintf (" bus_clock_rate_num: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_num);
kprintf (" bus_clock_rate_den: %ld\n", gPEClockFrequencyInfo.bus_clock_rate_den);
kprintf (" bus_to_cpu_rate_num: %ld\n", gPEClockFrequencyInfo.bus_to_cpu_rate_num);
kprintf (" bus_to_cpu_rate_den: %ld\n", gPEClockFrequencyInfo.bus_to_cpu_rate_den);
kprintf (" bus_to_dec_rate_num: %ld\n", gPEClockFrequencyInfo.bus_to_dec_rate_num);
kprintf (" bus_to_dec_rate_den: %ld\n", gPEClockFrequencyInfo.bus_to_dec_rate_den);
#endif
PE_call_timebase_callback ();
return;
}