AppleGracklePCI.cpp [plain text]
#include <IOKit/system.h>
#include <libkern/c++/OSContainers.h>
#include <IOKit/IODeviceMemory.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOLib.h>
#include <libkern/OSByteOrder.h>
#include "AppleGracklePCI.h"
#include <IOKit/assert.h>
#define super IOPCIBridge
OSDefineMetaClassAndStructors(AppleGracklePCI, IOPCIBridge)
bool AppleGracklePCI::start( IOService * provider )
{
IOPCIPhysicalAddress ioAddrCell;
IOPhysicalAddress ioPhys;
IOPhysicalAddress ioPhysLen;
OSArray * array;
IODeviceMemory::InitElement rangeList[ 3 ];
IORegistryEntry * bridge;
OSData * busProp;
IOPCIAddressSpace grackleSpace;
UInt32 picr1;
if( 0 == (lock = IOSimpleLockAlloc()))
return( false );
ioAddrCell.physHi.bits = 0;
ioAddrCell.physHi.s.space = kIOPCIIOSpace;
ioAddrCell.physMid = 0;
ioAddrCell.physLo = 0;
ioAddrCell.lengthHi = 0;
ioAddrCell.lengthLo = 0x10000;
bridge = provider;
if( ! IODTResolveAddressCell( bridge, (UInt32 *) &ioAddrCell,
&ioPhys, &ioPhysLen) ) {
IOLog("%s: couldn't find my base\n", getName());
return( false);
}
rangeList[0].start = ioPhys;
rangeList[0].length = ioPhysLen;
rangeList[1].start = ioPhys + 0x00c00000;
rangeList[1].length = 4;
rangeList[2].start = ioPhys + 0x00e00000;
rangeList[2].length = 4;
array = IODeviceMemory::arrayFromList( rangeList, 3 );
if( !array)
return( false);
provider->setDeviceMemory( array );
array->release();
ioMemory = (IODeviceMemory *) array->getObject( 0 );
if( (configAddrMap = provider->mapDeviceMemoryWithIndex( 1 )))
configAddr = (volatile UInt32 *) configAddrMap->getVirtualAddress();
if( (configDataMap = provider->mapDeviceMemoryWithIndex( 2 )))
configData = (volatile UInt8 *) configDataMap->getVirtualAddress();
if( !configAddr || !configData)
return( false);
busProp = (OSData *) bridge->getProperty("bus-range");
if( busProp)
primaryBus = *((UInt32 *) busProp->getBytesNoCopy());
if( provider->getProperty("set-loop-snoop")) {
grackleSpace.bits = 0x80000000;
picr1 = configRead32(grackleSpace, 0xA8);
picr1 |= (1 << 4);
configWrite32(grackleSpace, 0xA8, picr1);
}
registerService();
publishResource("AccessMPC106PerformanceRegister", this);
return( super::start( provider));
}
bool AppleGracklePCI::configure( IOService * provider )
{
bool ok;
ok = addBridgeMemoryRange( 0x80000000, 0x7f000000, true );
ok = addBridgeIORange( 0, 0x10000 );
return( super::configure( provider ));
}
void AppleGracklePCI::free()
{
if( configAddrMap)
configAddrMap->release();
if( configDataMap)
configDataMap->release();
if( lock)
IOSimpleLockFree( lock);
super::free();
}
IODeviceMemory * AppleGracklePCI::ioDeviceMemory( void )
{
return( ioMemory);
}
UInt8 AppleGracklePCI::firstBusNum( void )
{
return( primaryBus );
}
UInt8 AppleGracklePCI::lastBusNum( void )
{
return( firstBusNum() );
}
IOPCIAddressSpace AppleGracklePCI::getBridgeSpace( void )
{
IOPCIAddressSpace space;
space.bits = 0;
space.s.deviceNum = kBridgeSelfDevice;
return( space );
}
inline void AppleGracklePCI::setConfigSpace( IOPCIAddressSpace space,
UInt8 offset )
{
IOPCIAddressSpace addrCycle;
addrCycle = space;
addrCycle.s.reloc = 1;
addrCycle.s.registerNum = offset & 0xfc;
OSWriteSwapInt32( configAddr, 0, addrCycle.bits);
eieio();
OSReadSwapInt32( configAddr, 0 );
eieio();
}
UInt32 AppleGracklePCI::configRead32( IOPCIAddressSpace space,
UInt8 offset )
{
UInt32 data;
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
data = OSReadSwapInt32( configData, 0 );
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
return( data );
}
void AppleGracklePCI::configWrite32( IOPCIAddressSpace space,
UInt8 offset, UInt32 data )
{
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
OSWriteSwapInt32( configData, 0, data );
eieio();
(void) OSReadSwapInt32( configData, 0 );
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
}
UInt16 AppleGracklePCI::configRead16( IOPCIAddressSpace space,
UInt8 offset )
{
UInt16 data;
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
offset = (offset & 2);
data = OSReadSwapInt16( configData, offset );
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
return( data );
}
void AppleGracklePCI::configWrite16( IOPCIAddressSpace space,
UInt8 offset, UInt16 data )
{
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
offset = (offset & 2);
OSWriteSwapInt16( configData, offset, data );
eieio();
(void) OSReadSwapInt16( configData, offset );
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
}
UInt8 AppleGracklePCI::configRead8( IOPCIAddressSpace space,
UInt8 offset )
{
UInt8 data;
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
offset = (offset & 3);
data = configData[ offset ];
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
return( data );
}
void AppleGracklePCI::configWrite8( IOPCIAddressSpace space,
UInt8 offset, UInt8 data )
{
IOInterruptState ints;
ints = IOSimpleLockLockDisableInterrupt( lock );
setConfigSpace( space, offset );
offset = (offset & 3);
configData[ offset ] = data;
eieio();
data = configData[ offset ];
eieio();
IOSimpleLockUnlockEnableInterrupt( lock, ints );
}
IOReturn AppleGracklePCI::callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4)
{
if (functionName->isEqualTo("AccessMPC106PerformanceRegister")) {
return accessMPC106PerformanceRegister((bool)param1, (long)param2,
(unsigned long *)param3);
}
return super::callPlatformFunction(functionName, waitForFunction,
param1, param2, param3, param4);
}
enum {
kMCMonitorModeControl = 0,
kMCCommand,
kMCPerformanceMonitor0,
kMCPerformanceMonitor1,
kMCPerformanceMonitor2,
kMCPerformanceMonitor3
};
IOReturn AppleGracklePCI::accessMPC106PerformanceRegister(bool write,
long regNumber,
unsigned long *data)
{
IOPCIAddressSpace grackleSpace;
unsigned long offset;
switch (regNumber) {
case kMCMonitorModeControl : offset = kMPC106MMCR0; break;
case kMCCommand : offset = kMPC106CMDR0; break;
case kMCPerformanceMonitor0 : offset = kMPC106PMC0; break;
case kMCPerformanceMonitor1 : offset = kMPC106PMC1; break;
case kMCPerformanceMonitor2 : offset = kMPC106PMC2; break;
case kMCPerformanceMonitor3 : offset = kMPC106PMC3; break;
default : return kIOReturnBadArgument;
}
if (data == 0) return kIOReturnBadArgument;
grackleSpace.bits = 0x80000000;
if (write) {
configWrite32(grackleSpace, offset, *data);
} else {
*data = configRead32(grackleSpace, offset);
}
return kIOReturnSuccess;
}