diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-535E5C2A-DCFD-4BCB-B26B-11E88BDB8A8A.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-535E5C2A-DCFD-4BCB-B26B-11E88BDB8A8A.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,295 @@ + + + + + +TDmac Derived Class ImplementationImplementing the hardware-specific DMA controller. +

The TDmac class is part of the PIL. It is a +container for the DMA controller's channels, descriptors and descriptor +headers. It also defines virtual functions for operations that require +a PSL implementation.

+

You need to derive TDmac for each distinct type +of DMA controller on your device, and implement these virtual functions.

+

+ + + +Function +Mandatory/Conditional +Description + + + + +Transfer() +Mandatory +For single buffer and scatter/gather, this starts the DMA transfer. +For double buffer, this prepares the next fragment to transfer while +a current transfer is in operation + + +StopTransfer() +Mandatory +Stop the specified channel synchronously. Must not return to +the PSL implementation until the channel has stopped. + + +IsIdle() +Mandatory +Returns ETrue if specified channel is idle, +otherwise EFalse + + +MaxTransferSize() +Optional +Takes the parameters and evaluates the maximum transfer size +in bytes. + + +MemAlignMask() +Optional +This applies to DMA v1 only. + + +InitHwDes() +Optional +For scatter-gather, initialise the array of memory areas and +set up the first block of data to be transferred. + + +ChainHwDes() +Optional +For scatter-gather, add additional blocks of data to transfer +to the list of memory areas. + + +AppendHwDes() +Optional +For scatter-gather, add to the array of memory areas while +the transfer is active. This is used in particular for streaming data +where new descriptors can be added to the end of the chain while data +earlier in the train is being transferred. E.g. video streaming. + + +UnlinkHwDes() +Optional +For scatter-gather, remove items from the array of memory areas. + + +FailNext() +Optional +For a sequence of memory transfers, tell the next one to fail. + + +MissNextInterrupts() +Optional +DMA transfers start on the next interrupt, but sometimes you +want to skip the next interrupt for synchronisation or other reasons. + + +Extension() +Optional +Pass a command from the application/client down to the DMA +chipset. Hardware dependent. + + + +

+
Implement +the mandatory controller virtual functions

The TDmac class contains several pure virtual functions that +must be implemented by the PSL implementation:

    +
  • TDmac::Transfer()
  • +
  • TDmac::StopTransfer()
  • +
  • TDmac::IsIdle()
  • +

These functions start and stop transfers on a DMA channel +and are the main interface between the PIL and the PSL. The implementation +of these functions depends on the hardware available for performing +DMA, and on the characteristics used to specify a DMA transfer:

    +
  • the source and +destination addresses
  • +
  • the burst size
  • +
  • the maximum transfer +size
  • +
  • the transfer width, +i.e. number of bits per memory access
  • +
  • the memory alignment +and endianness.
  • +

The DMA Framework manages the transfer descriptors according +to the descriptor parameter passed into the TDmac constructor by the derived class constructor; the descriptor parameter +is a TDmac::SCreateInfo structure. The per-request +transfer parameters are passed into the descriptors for each request +issued by a driver.

+
The +transfer function: Transfer()

This function initiates a +previously constructed request on a specific channel. This is the +template implementation:

+void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr) +// +// Initiates a (previously constructed) request on a specific channel. +// + { + const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); + TDmaDesc* pD = HdrToHwDes(aHdr); + + __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD)); + + // Load the first descriptor address into the DMAC and start it + // by setting the RUN bit. + (void) *pD, (void) i; + + } +
+
The +stop transfer function: StopTransfer()

This is the template +implementation:

void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel) +// +// Stops a running channel. +// + { + const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); + + __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::StopTransfer channel=%d", i)); + + } +
+
The +function: IsIdle()

IsIdle() returns +the state of a given channel. This is the template implementation:

TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel) +// +// Returns the state of a given channel. +// + { + const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); + + __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::IsIdle channel=%d", i)); + + return ETrue; + } +
+
Implement +the non-mandatory controller virtual functions

The following +auxiliary functions are used to implement the scatter-gather transfer +mode behavior by creating and manipulating the linked list of transfer +fragment headers that describe a given scatter-gather transaction. +They are called by the TDmac base class functions +when the instance of the TDmac derived class reports +itself as being capable of scatter-gather operations.

    +
  • TDmac::InitHwDes()
  • +
  • TDmac::ChainHwDes()
  • +
  • TDmac::AppendHwDes()
  • +
+
First +scatter-gather support function: InitHwDes()

This is a +function for creating a scatter-gather list. From the information +in the passed-in request, the function sets up the descriptor with +that fragment's:

    +
  • source and destination +address
  • +
  • size
  • +
  • driver/DMA controller +specific transfer parameters: memory/peripheral, burst size, transfer +width.
  • +

This is the template implementation:

void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, + TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/) +// +// Sets up (from a passed in request) the descriptor with that fragment's source and destination address, +// the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral, +// burst size, transfer width). +// + { + TDmaDesc* pD = HdrToHwDes(aHdr); + + __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD)); + + // Unaligned descriptor? Error in generic layer! + __DMA_ASSERTD(IsHwDesAligned(pD)); + + pD-&>iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc); + pD-&>iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest); + pD-&>iCmd = DcmdReg(aCount, aFlags, aPslInfo); + pD-&>iDescAddr = TDmaDesc::KStopBitMask; + } +
+
Second +scatter-gather support function: ChainHwDes()

If the framework +needs to fragment the client’s request, either because of the transfer +size or because the memory is not a single contiguous block, then +the framework calls this function. It chains hardware descriptors +together by setting the next pointer of the original descriptor to +the physical address of the descriptor to be chained. It assumes that +the DMAC channel is quiescent when called.

This is the template +implementation:

void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr) +// +// Chains hardware descriptors together by setting the next pointer of the original descriptor +// to the physical address of the descriptor to be chained. +// + { + TDmaDesc* pD = HdrToHwDes(aHdr); + TDmaDesc* pN = HdrToHwDes(aNextHdr); + + __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN)); + + // Unaligned descriptor? Error in generic layer! + __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN)); + + pD-&>iDescAddr = DesLinToPhys(pN); + } +
+
Third +scatter-gather support function: AppendHwDes()

This function +is called by the TDmac base class when a driver +request is called for a channel that is still active, i.e. where the +intent is to provide data streaming so that the target device is constantly +provided with data; for example, an audio device playing a track. +In this case, the function provided by the derived class must:

    +
  • stop the DMAC to +prevent any corruption of the scatter-gather list while appending +the new fragment descriptor
  • +
  • append the new +descriptor
  • +
  • re-enable the channel, +ideally before the target has detected the gap in service.
  • +

This is the template implementation:

void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, + const SDmaDesHdr& aNewHdr) +// +// Appends a descriptor to the chain while the channel is running. +// + { + const TUint8 i = static_cast&<TUint8&>(aChannel.PslId()); + + TDmaDesc* pL = HdrToHwDes(aLastHdr); + TDmaDesc* pN = HdrToHwDes(aNewHdr); + + __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X", + i, pL, pN)); + // Unaligned descriptor? Error in generic layer! + __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN)); + + TPhysAddr newPhys = DesLinToPhys(pN); + + const TInt irq = NKern::DisableAllInterrupts(); + StopTransfer(aChannel); + + pL-&>iDescAddr = newPhys; + const TTemplateSgChannel& channel = static_cast&<const TTemplateSgChannel&&>(aChannel); + TDmaDesc* pD = channel.iTmpDes; + + (void) *pD, (void) i; + + NKern::RestoreInterrupts(irq); + + __KTRACE_OPT(KDMA, Kern::Printf("&<TTemplateDmac::AppendHwDes")); + } +
+
+DMA +Technology Guide +DMA +Implementation Guide +
\ No newline at end of file