AppleUltra33ATA.cpp [plain text]
#include "AppleUltra33ATA.h"
#include <IOKit/IODeviceTreeSupport.h>
#undef super
#define super IOATAStandardDriver
extern pmap_t kernel_pmap;
OSDefineMetaClassAndStructors( AppleUltra33ATA, IOATAStandardDriver )
static struct
{
UInt32 minDataAccess;
UInt32 minDataCycle;
} pioModes[] =
{
{ 165, 600 },
{ 125, 383 },
{ 100, 240 },
{ 80, 180 },
{ 70, 120 }
};
bool AppleUltra33ATA::configure( IOService *forProvider, ATAControllerInfo *controllerInfo )
{
provider = (IOPCIDevice *)forProvider;
busNum = 0;
ioMapATA[0] = provider->mapDeviceMemoryWithRegister( 0x10 + busNum * 8 + 0 );
if ( ioMapATA[0] == NULL ) return false;
ioBaseATA[0] = (volatile UInt32 *)ioMapATA[0]->getVirtualAddress();
ioMapATA[1] = provider->mapDeviceMemoryWithRegister( 0x10 + busNum * 8 + 4 );
if ( ioMapATA[1] == NULL ) return false;
ioBaseATA[1] = (volatile UInt32 *)ioMapATA[1]->getVirtualAddress();
pciWriteLong( 0x04, 0x05 );
dmaDescriptors = (Ultra646Descriptor *)kalloc(page_size);
if ( dmaDescriptors == 0 )
{
return false;
}
dmaDescriptorsPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) dmaDescriptors);
if ( (UInt32)dmaDescriptors & (page_size - 1) )
{
IOLog("AppleUltra33ATA::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__);
return false;
}
bzero( dmaDescriptors, page_size );
numDescriptors = page_size/sizeof(Ultra646Descriptor);
dmaMemoryCursor = IOBigMemoryCursor::withSpecification( 64*1024-2, 0xffffffff );
if ( dmaMemoryCursor == NULL )
{
return false;
}
bitBucketAddr = IOMalloc(32);
if ( bitBucketAddr == 0 )
{
return false;
}
bitBucketAddrPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) (((UInt32)bitBucketAddr + 0xf) & ~0x0f));
interruptEventSource = IOInterruptEventSource::interruptEventSource( (OSObject *) this,
(IOInterruptEventAction) &AppleUltra33ATA::interruptOccurred,
(IOService *) provider,
(int) 0 );
if ( interruptEventSource == NULL )
{
return false;
}
disableControllerInterrupts();
getWorkLoop()->addEventSource( interruptEventSource );
controllerInfo->maxDevicesSupported = 2;
controllerInfo->devicePrivateDataSize = 0;
controllerInfo->commandPrivateDataSize = 0;
controllerInfo->disableCancelCommands = false;
return true;
}
bool AppleUltra33ATA::calculateTiming( UInt32 unit, ATATiming *pTiming )
{
bool rc = false;
ideTimingRegs[unit].arttimReg = 0x40;
ideTimingRegs[unit].cmdtimReg = 0xA9;
switch ( pTiming->timingProtocol )
{
case kATATimingPIO:
rc = calculatePIOTiming( unit, pTiming );
break;
case kATATimingDMA:
rc = calculateDMATiming( unit, pTiming );
break;
case kATATimingUltraDMA33:
rc = calculateUltraDMATiming( unit, pTiming );
break;
default:
;
}
return rc;
}
bool AppleUltra33ATA::calculatePIOTiming( UInt32 unit, ATATiming *pTiming )
{
UInt32 accessTime;
UInt32 drwActClks, drwRecClks;
UInt32 drwActTime, drwRecTime;
accessTime = pioModes[pTiming->mode].minDataAccess;
drwActClks = accessTime / IDE_SYSCLK_NS;
drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0;
drwActTime = drwActClks * IDE_SYSCLK_NS;
drwRecTime = pioModes[pTiming->mode].minDataCycle - drwActTime;
drwRecClks = drwRecTime / IDE_SYSCLK_NS;
drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0;
if ( drwRecClks >= 16 )
drwRecClks = 1;
else if ( drwRecClks <= 1 )
drwRecClks = 16;
ideTimingRegs[unit].drwtimRegPIO = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f);
return true;
}
bool AppleUltra33ATA::calculateDMATiming( UInt32 unit, ATATiming *pTiming )
{
UInt32 accessTime;
UInt32 drwActClks, drwRecClks;
UInt32 drwActTime, drwRecTime;
ideTimingRegs[unit].udidetcrReg = 0;
accessTime = pTiming->minDataAccess;
drwActClks = accessTime / IDE_SYSCLK_NS;
drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0;
drwActTime = drwActClks * IDE_SYSCLK_NS;
drwRecTime = pTiming->minDataCycle - drwActTime;
drwRecClks = drwRecTime / IDE_SYSCLK_NS;
drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0;
if ( drwRecClks >= 16 )
drwRecClks = 1;
else if ( drwRecClks <= 1 )
drwRecClks = 16;
ideTimingRegs[unit].drwtimRegDMA = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f);
return true;
}
bool AppleUltra33ATA::calculateUltraDMATiming( UInt32 unit, ATATiming *pTiming )
{
UInt32 cycleClks;
UInt32 cycleTime;
cycleTime = pTiming->minDataCycle;
cycleClks = cycleTime / IDE_SYSCLK_NS;
cycleClks += (cycleTime % IDE_SYSCLK_NS) ? 1 : 0;
ideTimingRegs[unit].udidetcrReg = (0x01 << unit) | ((cycleClks-1) << ((!unit) ? 4 : 6)) ;
return true;
}
void AppleUltra33ATA::newDeviceSelected( IOATADevice *newDevice )
{
}
bool AppleUltra33ATA::selectTiming( UInt32 unit, ATATimingProtocol timingProtocol )
{
Ultra646Regs *cfgRegs;
UInt32 cfgByte;
cfgRegs = &ideTimingRegs[unit];
if ( busNum == 0 )
{
pciWriteByte( kUltra646CMDTIM, cfgRegs->cmdtimReg );
if ( unit == 0 )
{
pciWriteByte( kUltra646ARTTIM0, cfgRegs->arttimReg );
if ( timingProtocol == kATATimingPIO )
{
cfgByte = pciReadByte( kUltra646CNTRL );
cfgByte &= ~kUltra646CNTRL_Drive0ReadAhead;
cfgByte |= cfgRegs->cntrlReg;
pciWriteByte( kUltra646CNTRL, cfgByte );
pciWriteByte( kUltra646DRWTIM0, cfgRegs->drwtimRegPIO );
}
else if ( timingProtocol == kATATimingDMA )
{
pciWriteByte( kUltra646DRWTIM0, cfgRegs->drwtimRegDMA );
}
else if ( timingProtocol == kATATimingUltraDMA33 )
{
cfgByte = pciReadByte( kUltra646UDIDETCR0 );
cfgByte &= ~(kUltra646UDIDETCR0_Drive0UDMACycleTime | kUltra646UDIDETCR0_Drive0UDMAEnable);
cfgByte |= cfgRegs->udidetcrReg;
pciWriteByte( kUltra646UDIDETCR0, cfgByte );
}
}
else
{
pciWriteByte( kUltra646ARTTIM1, cfgRegs->arttimReg );
if ( timingProtocol == kATATimingPIO )
{
cfgByte = pciReadByte( kUltra646CNTRL );
cfgByte &= ~kUltra646CNTRL_Drive1ReadAhead;
cfgByte |= cfgRegs->cntrlReg;
pciWriteByte( kUltra646CNTRL, cfgByte );
pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegPIO );
}
else if ( timingProtocol == kATATimingDMA )
{
pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegDMA );
}
else if ( timingProtocol == kATATimingUltraDMA33 )
{
cfgByte = pciReadByte( kUltra646UDIDETCR0 );
cfgByte &= ~(kUltra646UDIDETCR0_Drive1UDMACycleTime | kUltra646UDIDETCR0_Drive1UDMAEnable);
cfgByte |= cfgRegs->udidetcrReg;
pciWriteByte( kUltra646UDIDETCR0, cfgByte );
}
}
}
else
{
pciWriteByte( kUltra646CMDTIM, cfgRegs->cmdtimReg );
if ( unit == 0 )
{
cfgByte = pciReadByte( kUltra646ARTTIM23 );
cfgByte &= ~(kUltra646ARTTIM23_Drive2ReadAhead | kUltra646ARTTIM23_AddrSetup);
cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg;
pciWriteByte( kUltra646ARTTIM23, cfgByte );
if ( timingProtocol == kATATimingPIO )
{
pciWriteByte( kUltra646DRWTIM2, cfgRegs->drwtimRegPIO );
}
else if ( timingProtocol == kATATimingDMA )
{
pciWriteByte( kUltra646DRWTIM1, cfgRegs->drwtimRegDMA );
}
else if ( timingProtocol == kATATimingUltraDMA33 )
{
cfgByte = pciReadByte( kUltra646UDIDETCR1 );
cfgByte &= ~(kUltra646UDIDETCR1_Drive2UDMACycleTime | kUltra646UDIDETCR1_Drive2UDMAEnable);
cfgByte |= cfgRegs->udidetcrReg;
pciWriteByte( kUltra646UDIDETCR1, cfgByte );
}
}
else
{
cfgByte = pciReadByte( kUltra646ARTTIM23 );
cfgByte &= ~(kUltra646ARTTIM23_Drive3ReadAhead | kUltra646ARTTIM23_AddrSetup);
cfgByte |= (cfgRegs->cntrlReg >> 4) | cfgRegs->arttimReg;
pciWriteByte( kUltra646ARTTIM23, cfgByte );
if ( timingProtocol == kATATimingPIO )
{
pciWriteByte( kUltra646DRWTIM3, cfgRegs->drwtimRegPIO );
}
else if ( timingProtocol == kATATimingDMA )
{
pciWriteByte( kUltra646DRWTIM3, cfgRegs->drwtimRegDMA );
}
else if ( timingProtocol == kATATimingUltraDMA33 )
{
cfgByte = pciReadByte( kUltra646UDIDETCR1 );
cfgByte &= ~(kUltra646UDIDETCR1_Drive3UDMACycleTime | kUltra646UDIDETCR1_Drive3UDMAEnable);
cfgByte |= cfgRegs->udidetcrReg;
pciWriteByte( kUltra646UDIDETCR1, cfgByte );
}
}
}
return true;
}
void AppleUltra33ATA::interruptOccurred()
{
UInt32 intReg;
UInt32 cfgReg;
intReg = (busNum == 0) ? kUltra646CFR : kUltra646ARTTIM23;
cfgReg = pciReadByte( intReg );
pciWriteByte( intReg, cfgReg );
intReg = (busNum == 0) ? kUltra646BMIDESR0 : kUltra646BMIDESR1;
cfgReg = pciReadByte( intReg );
pciWriteByte( intReg, cfgReg );
super::interruptOccurred();
enableControllerInterrupts();
}
bool AppleUltra33ATA::programDma( IOATAStandardCommand *cmd )
{
IOMemoryDescriptor *memoryDesc;
IOPhysicalSegment physSeg;
IOByteCount offset;
UInt32 i;
UInt32 bytesLeft;
UInt32 len;
Ultra646Descriptor *dmaDesc;
UInt32 startSeg, endSeg;
cmd->getPointers( &memoryDesc, &dmaReqLength, &dmaIsWrite );
if ( dmaReqLength == 0 )
{
return true;
}
offset = 0;
dmaDesc = dmaDescriptors;
bytesLeft = dmaReqLength;
for (i = 0; i < numDescriptors-1; i++, dmaDesc++ )
{
if ( dmaMemoryCursor->getPhysicalSegments( memoryDesc, offset, &physSeg, 1 ) != 1 )
{
break;
}
startSeg = (physSeg.location & ~0xffff);
endSeg = (physSeg.location + physSeg.length - 1) & ~0xffff;
OSWriteSwapInt32( &dmaDesc->start, 0, physSeg.location);
if ( startSeg == endSeg )
{
OSWriteSwapInt32( &dmaDesc->length, 0, physSeg.length );
}
else
{
len = (-physSeg.location & 0xffff);
OSWriteSwapInt32( &dmaDesc->length, 0, len );
dmaDesc++;
i++;
OSWriteSwapInt32( &dmaDesc->start, 0, physSeg.location + len );
OSWriteSwapInt32( &dmaDesc->length, 0, physSeg.length - len );
}
bytesLeft -= physSeg.length;
offset += physSeg.length;
}
if ( bytesLeft != 0 )
{
return false;
}
if ( dmaReqLength & 1 )
{
if ( i == numDescriptors ) return false;
dmaDesc++;
OSWriteSwapInt32( &dmaDesc->start, 0, bitBucketAddrPhys );
OSWriteSwapInt32( &dmaDesc->length, 0, 1 );
}
dmaDesc--;
dmaDesc->length |= 0x80;
pciWriteLong( ((busNum == 0) ? kUltra646DTPR0 : kUltra646DTPR1), dmaDescriptorsPhys );
return true;
}
bool AppleUltra33ATA::startDma( IOATAStandardCommand * )
{
UInt32 reg;
UInt32 cfgReg;
UInt32 startMask;
UInt32 writeMask;
if ( dmaReqLength != 0 )
{
reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1;
startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY;
writeMask = (busNum == 0) ? kUltra646BMIDECR0_PCIWritePRI : kUltra646BMIDECR1_PCIWriteSDY;
cfgReg = pciReadByte( reg );
cfgReg &= ~writeMask;
cfgReg |= startMask | ((dmaIsWrite == false) ? writeMask : 0);
pciWriteByte( reg, cfgReg );
}
return true;
}
bool AppleUltra33ATA::stopDma( IOATAStandardCommand *, UInt32 *transferCount )
{
UInt32 reg;
UInt32 cfgReg;
UInt32 startMask;
*transferCount = 0;
if ( dmaReqLength == 0 )
{
return true;
}
reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1;
startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY;
cfgReg = pciReadByte( reg );
cfgReg &= ~startMask;
pciWriteByte( reg, cfgReg );
*transferCount = dmaReqLength;
return true;
}
bool AppleUltra33ATA::checkDmaActive()
{
UInt32 reg;
UInt32 cfgReg;
UInt32 activeMask;
reg = (busNum == 0) ? kUltra646BMIDESR0 : kUltra646BMIDESR1;
activeMask = (busNum == 0) ? kUltra646BMIDESR0_DMAActivePRI : kUltra646BMIDESR1_DMAActiveSDY;
cfgReg = pciReadByte( reg );
return ((cfgReg & activeMask) != 0);
}
bool AppleUltra33ATA::resetDma()
{
UInt32 reg;
UInt32 cfgReg;
UInt32 startMask;
reg = (busNum == 0) ? kUltra646BMIDECR0 : kUltra646BMIDECR1;
startMask = (busNum == 0) ? kUltra646BMIDECR0_StartDMAPRI : kUltra646BMIDECR1_StartDMASDY;
cfgReg = pciReadByte( reg );
cfgReg &= ~startMask;
pciWriteByte( reg, cfgReg );
return true;
}
void AppleUltra33ATA::disableControllerInterrupts()
{
interruptEventSource->disable();
}
void AppleUltra33ATA::enableControllerInterrupts()
{
interruptEventSource->enable();
}
void AppleUltra33ATA::free()
{
UInt32 i;
if ( interruptEventSource != 0 )
{
interruptEventSource->disable();
interruptEventSource->release();
}
for (i = 0; i < 2; i++ )
{
if ( ioMapATA[i] != 0 ) ioMapATA[i]->release();
}
if ( dmaDescriptors != 0 )
{
kfree( (vm_offset_t)dmaDescriptors, page_size );
}
}
void AppleUltra33ATA::writeATAReg( UInt32 regIndex, UInt32 regValue )
{
if ( regIndex == 0 )
{
*(volatile UInt16 *)ioBaseATA[0] = regValue;
}
else if ( regIndex < kATARegDeviceControl )
{
*((volatile UInt8 *)ioBaseATA[0] + regIndex) = regValue;
}
else
{
*((volatile UInt8 *)ioBaseATA[1] + regIndex - kATARegDeviceControl + 2) = regValue;
}
eieio();
}
UInt32 AppleUltra33ATA::readATAReg( UInt32 regIndex )
{
if ( regIndex == 0 )
{
return *(volatile UInt16 *)ioBaseATA[0];
}
else if ( regIndex < kATARegDeviceControl )
{
return *((volatile UInt8 *)ioBaseATA[0] + regIndex);
}
return *((volatile UInt8 *)ioBaseATA[1] + regIndex - kATARegDeviceControl + 2);
}
UInt32 AppleUltra33ATA::pciReadByte( UInt32 reg )
{
volatile union
{
unsigned long word;
unsigned char byte[4];
} data;
data.word = provider->configRead32( reg );
return data.byte[3 - (reg & 0x03)];
}
void AppleUltra33ATA::pciWriteByte( UInt32 reg, UInt32 value )
{
volatile union
{
unsigned long word;
unsigned char byte[4];
} data;
UInt32 regWord;
regWord = reg & ~0x03;
data.word = provider->configRead32( regWord );
data.word = OSReadSwapInt32( &data.word, 0 );
switch (regWord)
{
case kUltra646CFR:
data.byte[kUltra646CFR & 0x03] &= ~kUltra646CFR_IDEIntPRI;
break;
case kUltra646DRWTIM0:
data.byte[kUltra646ARTTIM23 & 0x03] &= ~kUltra646ARTTIM23_IDEIntSDY;
break;
case kUltra646BMIDECR0:
data.byte[kUltra646MRDMODE & 0x03 ] &= ~(kUltra646MRDMODE_IDEIntPRI | kUltra646MRDMODE_IDEIntSDY);
data.byte[kUltra646BMIDESR0 & 0x03] &= ~(kUltra646BMIDESR0_DMAIntPRI | kUltra646BMIDESR0_DMAErrorPRI);
break;
case kUltra646BMIDECR1:
data.byte[kUltra646BMIDESR1 & 0x03] &= ~(kUltra646BMIDESR1_DMAIntSDY | kUltra646BMIDESR1_DMAErrorSDY);
break;
}
data.byte[reg & 0x03] = value;
data.word = OSReadSwapInt32(&data.word, 0);
provider->configWrite32( regWord, data.word );
}
UInt32 AppleUltra33ATA::pciReadLong( UInt32 reg )
{
return provider->configRead32( reg );
}
void AppleUltra33ATA::pciWriteLong( UInt32 reg, UInt32 value )
{
provider->configWrite32( reg, value );
}
bool AppleUltra33ATA::attach( IOService * provider )
{
if ( super::attach(provider) )
{
pathProvider = OSDynamicCast(IOService, provider->getChildEntry(gIODTPlane));
if ( pathProvider )
{
setLocation(pathProvider->getLocation(gIODTPlane), gIODTPlane);
setName(pathProvider->getName(gIODTPlane), gIODTPlane);
attachToParent(provider, gIODTPlane);
pathProvider->retain();
pathProvider->detachFromParent(provider, gIODTPlane);
}
return true;
}
return false;
}
void AppleUltra33ATA::detach( IOService * provider )
{
if ( pathProvider )
{
detachFromParent(provider, gIODTPlane);
pathProvider->attachToParent(provider, gIODTPlane);
pathProvider->release();
}
super::detach(provider);
}