#include <IOKit/platform/ApplePlatformExpert.h>
#include "UniN.h"
#include <sys/cdefs.h>
__BEGIN_DECLS
#include <mach/mach_types.h>
extern vm_offset_t ml_io_map(vm_offset_t phys_addr, vm_size_t size);
__END_DECLS
#define super IOService
OSDefineMetaClassAndStructors(AppleUniN,ApplePlatformExpert)
bool AppleUniN::start ( IOService * nub )
{
OSData *tmpData;
UInt32 uniNArbCtrl, uniNBaseAddressTemp, uniNMPCIMemTimeout;
IOInterruptState intState;
IOPlatformFunction *func;
const OSSymbol *functionSymbol = OSSymbol::withCString("InstantiatePlatformFunctions");
SInt32 retval;
provider = nub;
tmpData = OSDynamicCast(OSData, provider->getProperty("reg"));
if (tmpData == 0) return false;
uniNBaseAddressTemp = ((UInt32 *)tmpData->getBytesNoCopy())[0];
uniNBaseAddress = (UInt32 *)ml_io_map(uniNBaseAddressTemp, 0x3200);
if (uniNBaseAddress == 0) return false;
mutex = IOSimpleLockAlloc();
if (mutex != NULL)
IOSimpleLockInit( mutex );
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
uniNVersion = readUniNReg(kUniNVersion);
if (uniNVersion < kUniNVersion150)
{
uniNArbCtrl = readUniNReg(kUniNArbCtrl);
uniNArbCtrl &= ~kUniNArbCtrlQAckDelayMask;
if (uniNVersion < kUniNVersion107) {
uniNArbCtrl |= kUniNArbCtrlQAckDelay105 << kUniNArbCtrlQAckDelayShift;
} else {
uniNArbCtrl |= kUniNArbCtrlQAckDelay << kUniNArbCtrlQAckDelayShift;
}
writeUniNReg(kUniNArbCtrl, uniNArbCtrl);
}
if ( ((uniNVersion >= kUniNVersion150) && (uniNVersion <= kUniNVersion200)) ||
(uniNVersion == kUniNVersionPangea) )
{
uniNMPCIMemTimeout = readUniNReg(kUniNMPCIMemTimeout);
uniNMPCIMemTimeout &= ~kUniNMPCIMemTimeoutMask;
uniNMPCIMemTimeout |= kUniNMPCIMemGrantTime;
writeUniNReg(kUniNMPCIMemTimeout, uniNMPCIMemTimeout);
}
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
if (callPlatformFunction ("PlatformIsPortable", true, (void *) &hostIsMobile, (void *)0,
(void *)0, (void *)0) != kIOReturnSuccess)
hostIsMobile = false;
retval = provider->getPlatform()->callPlatformFunction (functionSymbol, false, (void *)provider,
(void *)&platformFuncArray, (void *)0, (void *)0);
if (retval == kIOReturnSuccess && (platformFuncArray != NULL)) {
unsigned int i;
for (i = 0; i < platformFuncArray->getCount(); i++)
if (func = OSDynamicCast (IOPlatformFunction, platformFuncArray->getObject(i)))
if (func->getCommandFlags() & kIOPFFlagOnDemand)
func->publishPlatformFunction (this);
}
createNubs(this, provider->getChildIterator( gIODTPlane ));
registerService();
return super::start(provider);
}
void AppleUniN::free ()
{
if (platformFuncArray) {
platformFuncArray->flushCollection();
platformFuncArray->release();
}
if (mutex != NULL)
IOSimpleLockFree( mutex );
return;
}
IOReturn AppleUniN::callPlatformFunction(const OSSymbol *functionName, bool waitForFunction,
void *param1, void *param2, void *param3, void *param4)
{
if (functionName->isEqualTo("safeReadRegUInt32"))
{
UInt32 *returnval = (UInt32 *)param2;
*returnval = safeReadRegUInt32((UInt32)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo("safeWriteRegUInt32"))
{
safeWriteRegUInt32((UInt32)param1, (UInt32)param2, (UInt32)param3);
return kIOReturnSuccess;
}
if (functionName->isEqualTo(kUniNSetPowerState))
{
uniNSetPowerState((UInt32)param1);
return kIOReturnSuccess;
}
if (functionName->isEqualTo ("setupUATAforSleep"))
return setupUATAforSleep();
if (platformFuncArray) {
UInt32 i;
IOPlatformFunction *pfFunc;
for (i = 0; i < platformFuncArray->getCount(); i++)
if (pfFunc = OSDynamicCast (IOPlatformFunction, platformFuncArray->getObject(i)))
if (pfFunc->platformFunctionMatch (functionName, kIOPFFlagOnDemand, NULL))
return (performFunction (pfFunc, param1, param2, param3, param4) ? kIOReturnSuccess : kIOReturnBadArgument);
}
return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
}
IOReturn AppleUniN::callPlatformFunction(const char *functionName, bool waitForFunction,
void *param1, void *param2, void *param3, void *param4)
{
IOReturn result = kIOReturnNoMemory;
const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
if (functionSymbol != 0) {
result = callPlatformFunction(functionSymbol, waitForFunction,
param1, param2, param3, param4);
functionSymbol->release();
}
return result;
}
IOReturn AppleUniN::setupUATAforSleep ()
{
IOService *uATANub;
bool result;
result = kIOReturnUnsupported;
if ((uniNVersion == kUniNVersionIntrepid) && hostIsMobile) {
uATANub = OSDynamicCast (IOService, provider->fromPath("/pci@F4000000/ata-6@D", gIODTPlane));
if (uATANub) {
char path[256];
int length;
length = 256;
*path = '\0';
uATANub->getPath (path, &length, gIOServicePlane);
if (uATABaseAddressMap = uATANub->mapDeviceMemoryWithIndex(0)) {
uATABaseAddress = (volatile UInt32 *) uATABaseAddressMap->getVirtualAddress();
result = kIOReturnSuccess;
}
}
}
return result;
}
UInt32 AppleUniN::readUniNReg(UInt32 offset)
{
return uniNBaseAddress[offset >> 2];
}
void AppleUniN::writeUniNReg(UInt32 offset, UInt32 data)
{
uniNBaseAddress[offset >> 2] = data;
OSSynchronizeIO();
return;
}
UInt32 AppleUniN::safeReadRegUInt32(UInt32 offset)
{
IOInterruptState intState;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
UInt32 currentReg = readUniNReg(offset);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
return (currentReg);
}
void AppleUniN::safeWriteRegUInt32(UInt32 offset, UInt32 mask, UInt32 data)
{
IOInterruptState intState;
UInt32 currentReg;
if ( mutex != NULL )
intState = IOSimpleLockLockDisableInterrupt(mutex);
if (mask == ~0UL) currentReg = data;
else {
currentReg = readUniNReg(offset);
currentReg = (currentReg & ~mask) | (data & mask);
}
writeUniNReg (offset, currentReg);
if ( mutex != NULL )
IOSimpleLockUnlockEnableInterrupt(mutex, intState);
return;
}
void AppleUniN::enableUniNEthernetClock(bool enable, IOService *nub)
{
if (enable)
configureUniNPCIDevice(nub);
safeWriteRegUInt32 (kUniNClockControl, kUniNEthernetClockEnable,
enable ? kUniNEthernetClockEnable : 0);
return;
}
void AppleUniN::enableUniNFireWireClock(bool enable, IOService *nub)
{
if (enable)
configureUniNPCIDevice(nub);
safeWriteRegUInt32 (kUniNClockControl, kUniNFirewireClockEnable,
enable ? kUniNFirewireClockEnable : 0);
return;
}
void AppleUniN::configureUniNPCIDevice (IOService *nub)
{
OSData *cacheData, *latencyData;
IOPCIDevice *provider;
if (nub) provider = OSDynamicCast(IOPCIDevice, nub);
else provider = NULL;
if (provider) {
cacheData = (OSData *)provider->getProperty (kIOPCICacheLineSize);
latencyData = (OSData *)provider->getProperty (kIOPCITimerLatency);
if (cacheData || latencyData) {
UInt32 configData;
configData = provider->configRead32 (kIOPCIConfigCacheLineSize);
if (cacheData)
configData = (configData & 0xFFFFFF00) | *(char *) cacheData->getBytesNoCopy();
if (latencyData)
configData = (configData & 0xFFFF00FF) | ((*(char *) latencyData->getBytesNoCopy()) << 8);
provider->configWrite32 (kIOPCIConfigCacheLineSize, configData);
}
}
return;
}
void AppleUniN::uniNSetPowerState (UInt32 state)
{
UInt32 uataFCR;
if (state == kUniNNormal) {
safeWriteRegUInt32(kUniNPowerMngmnt, ~0UL, kUniNNormal);
safeWriteRegUInt32(kUniNHWInitState, ~0UL, kUniNHWInitStateRunning);
if (uataBusWasReset) {
uataBusWasReset = false;
uataFCR = *(UInt32 *)(uATABaseAddress + 0); uataFCR |= (kUniNUATAReset | kUniNUATAEnable); *(UInt32 *)(uATABaseAddress + 0) = uataFCR; OSSynchronizeIO();
}
} else if (state == kUniNIdle2) {
safeWriteRegUInt32(kUniNHWInitState, ~0UL, kUniNHWInitStateSleeping);
safeWriteRegUInt32(kUniNPowerMngmnt, ~0UL, kUniNIdle2);
} else if (state == kUniNSleep) {
if ((uniNVersion == kUniNVersionIntrepid) && hostIsMobile && uATABaseAddress) {
uataFCR = *(UInt32 *)(uATABaseAddress + 0); uataFCR &= ~(kUniNUATAReset | kUniNUATAEnable); *(UInt32 *)(uATABaseAddress + 0) = uataFCR; OSSynchronizeIO();
uataBusWasReset = true;
}
safeWriteRegUInt32(kUniNHWInitState, ~0UL, kUniNHWInitStateSleeping);
safeWriteRegUInt32(kUniNPowerMngmnt, ~0UL, kUniNSleep);
}
return;
}
enum
{
kMCMonitorModeControl = 0,
kMCCommand,
kMCPerformanceMonitor0,
kMCPerformanceMonitor1,
kMCPerformanceMonitor2,
kMCPerformanceMonitor3
};
IOReturn AppleUniN::accessUniN15PerformanceRegister(bool write, long regNumber, UInt32 *data)
{
UInt32 offset;
if (uniNVersion < kUniNVersion150) return kIOReturnUnsupported;
switch (regNumber) {
case kMCMonitorModeControl : offset = kUniNMMCR; break;
case kMCCommand : offset = kUniNMCMDR; break;
case kMCPerformanceMonitor0 : offset = kUniNMPMC1; break;
case kMCPerformanceMonitor1 : offset = kUniNMPMC2; break;
case kMCPerformanceMonitor2 : offset = kUniNMPMC3; break;
case kMCPerformanceMonitor3 : offset = kUniNMPMC4; break;
default : return kIOReturnBadArgument;
}
if (data == 0) return kIOReturnBadArgument;
if (write) {
writeUniNReg(offset, *data);
} else {
*data = readUniNReg(offset);
}
return kIOReturnSuccess;
}
bool AppleUniN::performFunction(const IOPlatformFunction *func, void *cpfParam1,
void *cpfParam2, void *cpfParam3, void *cpfParam4)
{
bool ret;
IOPlatformFunctionIterator *iter;
UInt32 offset, value, valueLen, mask, maskLen, data, writeLen,
cmd, cmdLen, result, pHandle, lastCmd,
param1, param2, param3, param4, param5,
param6, param7, param8, param9, param10;
IOPCIDevice *nub;
if (func == 0) return(false);
if (!(iter = ((IOPlatformFunction *)func)->getCommandIterator()))
return false;
ret = true;
while (iter->getNextCommand (&cmd, &cmdLen, ¶m1, ¶m2, ¶m3, ¶m4,
¶m5, ¶m6, ¶m7, ¶m8, ¶m9, ¶m10, &result) && ret) {
if (result != kIOPFNoError)
ret = false;
else
switch (cmd) {
case kCommandWriteReg32:
offset = param1;
value = param2;
mask = param3;
if (mask != 0xFFFFFFFF) {
data = readUniNReg (offset);
data &= mask;
data |= value;
} else data = value;
writeUniNReg(offset, data);
break;
case kCommandReadConfig:
offset = param1;
valueLen = param2;
if (valueLen != 4) {
IOLog ("AppleUniN::performFunction config reads cannot handle anything other than 4 bytes, found length %ld\n", valueLen);
ret = false;
}
if (!nub) {
if (!pHandle) {
IOLog ("AppleUniN::performFunction config read requires pHandle to locate nub\n");
ret = false;
}
nub = findNubForPHandle (pHandle);
if (!nub) {
IOLog ("AppleUniN::performFunction config read cannot find nub for pHandle 0x%08lx\n", pHandle);
ret = false;
}
}
data = nub->configRead32 (offset);
if (cpfParam1)
*(UInt32 *)cpfParam1 = data;
lastCmd = kCommandReadConfig;
break;
case kCommandRMWConfig:
if (lastCmd != kCommandReadConfig) {
IOLog ("AppleUniN::performFunction - config modify/write requires prior read\n");
ret = false;
}
offset = param1;
maskLen = param2;
valueLen = param3;
writeLen = param4;
if (writeLen != 4) {
IOLog ("AppleUniN::performFunction config read/modify/write cannot handle anything other than 4 bytes, found length %ld\n", writeLen);
ret = false;
}
mask = *(UInt32 *)param5;
value = *(UInt32 *)param6;
if (!nub) {
if (!pHandle) {
IOLog ("AppleUniN::performFunction config read/modify/write requires pHandle to locate nub\n");
ret = false;
}
nub = findNubForPHandle (pHandle);
if (!nub) {
IOLog ("AppleUniN::performFunction config read/modify/write cannot find nub for pHandle 0x%08lx\n", pHandle);
ret = false;
}
}
data &= mask;
data |= value;
nub->configWrite32 (offset, data);
break;
default:
IOLog("AppleUniN::performFunction got unsupported command %08lx\n", cmd);
ret = false;
break;
}
}
iter->release();
return(ret);
}
IOPCIDevice* AppleUniN::findNubForPHandle( UInt32 pHandleValue )
{
IORegistryIterator* iterator;
IORegistryEntry* matchingEntry = NULL;
iterator = IORegistryIterator::iterateOver( gIODTPlane, kIORegistryIterateRecursively );
if ( iterator == NULL )
return( NULL );
while ( ( matchingEntry = iterator->getNextObject() ) != NULL ) {
OSData* property;
if ( ( property = OSDynamicCast( OSData, matchingEntry->getProperty( "AAPL,phandle" ) ) ) != NULL )
if ( pHandleValue == *( ( UInt32 * ) property->getBytesNoCopy() ) )
break;
}
iterator->release();
return( OSDynamicCast (IOPCIDevice, matchingEntry));
}