Update contrib.
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // bsptemplate/asspvariant/template_assp/dmapsl.cpp
15 // Template DMA Platform Specific Layer (PSL).
20 #include <kernel/kern_priv.h>
21 #include <template_assp.h> // /assp/template_assp/
23 #include <drivers/dma.h>
24 #include <drivers/dma_hai.h>
28 static const char KDmaPanicCat[] = "DMA PSL - " __FILE__;
30 static const TInt KMaxTransferLen = 0x1FE0; // max transfer length for this DMAC
31 static const TInt KMemAlignMask = 7; // memory addresses passed to DMAC must be multiple of 8
32 static const TInt KChannelCount = 16; // we got 16 channels
33 static const TInt KDesCount = 160; // Initial DMA descriptor count
38 // Hardware DMA descriptor
42 enum {KStopBitMask = 1};
51 //////////////////////////////////////////////////////////////////////////////
53 //////////////////////////////////////////////////////////////////////////////
56 TO DO: Fill in to provide information to the V1 test harness (t_dma.exe)
58 TDmaTestInfo TestInfo =
72 EXPORT_C const TDmaTestInfo& DmaTestInfo()
81 TO DO: Fill in to provide information to the V2 test harness (t_dma2.exe)
83 TDmaV2TestInfo TestInfov2 =
96 EXPORT_C const TDmaV2TestInfo& DmaTestInfoV2()
101 //////////////////////////////////////////////////////////////////////////////
103 //////////////////////////////////////////////////////////////////////////////
105 inline TBool IsHwDesAligned(TAny* aDes)
107 // Checks whether given hardware descriptor is 16-bytes aligned.
110 return ((TLinAddr)aDes & 0xF) == 0;
114 static TUint32 DmaCmdReg(TUint aCount, TUint aFlags, TUint32 aSrcPslInfo, TUint32 aDstPslInfo)
116 // Returns value to set in DMA command register or in descriptor command field.
119 // TO DO: Construct CMD word from input values.
120 // The return value should reflect the actual control word.
121 return (aCount | aFlags | aSrcPslInfo | aDstPslInfo);
125 //////////////////////////////////////////////////////////////////////////////
126 // Derived Channel (Scatter/Gather)
127 //////////////////////////////////////////////////////////////////////////////
129 class TTemplateSgChannel : public TDmaSgChannel
133 TPhysAddr iTmpDesPhysAddr;
137 //////////////////////////////////////////////////////////////////////////////
138 // Derived Controller Class
139 //////////////////////////////////////////////////////////////////////////////
141 class TTemplateDmac : public TDmac
147 // from TDmac (PIL pure virtual)
148 virtual void StopTransfer(const TDmaChannel& aChannel);
149 virtual TBool IsIdle(const TDmaChannel& aChannel);
150 virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags,
151 TUint aDstFlags, TUint32 aPslInfo);
152 virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aSrcFlags,
153 TUint aDstFlags, TUint32 aPslInfo);
154 // from TDmac (PIL virtual)
155 virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
156 virtual TInt InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
157 virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
158 virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
159 const SDmaDesHdr& aNewHdr);
160 virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
162 static void Isr(TAny* aThis);
163 inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
165 static const SCreateInfo KInfo;
167 TTemplateSgChannel iChannels[KChannelCount];
171 static TTemplateDmac Controller;
174 const TDmac::SCreateInfo TTemplateDmac::KInfo =
177 KDesCount, // iDesCount
178 sizeof(TDmaDesc), // iDesSize
179 EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs
183 TTemplateDmac::TTemplateDmac()
191 TInt TTemplateDmac::Create()
193 // Second phase construction.
196 TInt r = TDmac::Create(KInfo); // Base class Create()
199 __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
200 for (TInt i=0; i < KChannelCount; ++i)
202 TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
203 iChannels[i].iTmpDes = pD;
204 iChannels[i].iTmpDesPhysAddr = HwDesLinToPhys(pD);
205 iFreeHdr = iFreeHdr->iNext;
207 r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
210 // TO DO: Map DMA clients (requests) to DMA channels here.
212 r = Interrupt::Enable(EAsspIntIdDma);
219 void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
221 // Initiates a (previously constructed) request on a specific channel.
224 const TUint8 i = static_cast<TUint8>(aChannel.PslId());
225 TDmaDesc* pD = HdrToHwDes(aHdr);
227 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
229 // TO DO (for instance): Load the first descriptor address into the DMAC and start it
230 // by setting the RUN bit.
231 (void) *pD, (void) i;
236 void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
238 // Stops a running channel.
241 const TUint8 i = static_cast<TUint8>(aChannel.PslId());
243 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
245 // TO DO (for instance): Clear the RUN bit of the channel.
251 TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
253 // Returns the state of a given channel.
256 const TUint8 i = static_cast<TUint8>(aChannel.PslId());
258 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
260 // TO DO (for instance): Return the state of the RUN bit of the channel.
261 // The return value should reflect the actual state.
268 TUint TTemplateDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/,
269 TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
271 // Returns the maximum transfer length in bytes for a given transfer.
274 // TO DO: Determine the proper return value, based on the arguments.
277 return KMaxTransferLen;
281 TUint TTemplateDmac::AddressAlignMask(TDmaChannel& aChannel, TUint /*aSrcFlags*/,
282 TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
284 // Returns the memory buffer alignment restrictions mask for a given transfer.
287 // TO DO: Determine the proper return value, based on the arguments.
290 return KMemAlignMask;
294 TInt TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs)
296 // Sets up (from a passed in request) the descriptor with that fragment's
297 // source and destination address, the fragment size, and the (driver/DMA
298 // controller) specific transfer parameters (mem/peripheral, burst size,
302 TDmaDesc* pD = HdrToHwDes(aHdr);
304 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
306 // Unaligned descriptor? Bug in generic layer!
307 __DMA_ASSERTD(IsHwDesAligned(pD));
309 const TDmaTransferConfig& src = aTransferArgs.iSrcConfig;
310 const TDmaTransferConfig& dst = aTransferArgs.iDstConfig;
311 pD->iSrcAddr = (src.iFlags & KDmaPhysAddr) ? src.iAddr : Epoc::LinearToPhysical(src.iAddr);
312 pD->iDestAddr = (dst.iFlags & KDmaPhysAddr) ? dst.iAddr : Epoc::LinearToPhysical(dst.iAddr);
313 pD->iCmd = DmaCmdReg(aTransferArgs.iTransferCount, aTransferArgs.iFlags,
314 src.iPslTargetInfo, dst.iPslTargetInfo);
315 pD->iDescAddr = TDmaDesc::KStopBitMask;
321 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
323 // Chains hardware descriptors together by setting the next pointer of the original descriptor
324 // to the physical address of the descriptor to be chained.
327 TDmaDesc* pD = HdrToHwDes(aHdr);
328 TDmaDesc* pN = HdrToHwDes(aNextHdr);
330 __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
332 // Unaligned descriptor? Bug in generic layer!
333 __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
335 // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
337 pD->iDescAddr = HwDesLinToPhys(pN);
341 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
342 const SDmaDesHdr& aNewHdr)
344 // Appends a descriptor to the chain while the channel is running.
347 const TUint8 i = static_cast<TUint8>(aChannel.PslId());
349 TDmaDesc* pL = HdrToHwDes(aLastHdr);
350 TDmaDesc* pN = HdrToHwDes(aNewHdr);
352 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
354 // Unaligned descriptor? Bug in generic layer!
355 __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
357 TPhysAddr newPhys = HwDesLinToPhys(pN);
359 const TInt irq = NKern::DisableAllInterrupts();
360 StopTransfer(aChannel);
362 pL->iDescAddr = newPhys;
363 const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
364 TDmaDesc* pD = channel.iTmpDes;
366 // TO DO: Implement the appropriate algorithm for appending a descriptor here.
367 (void) *pD, (void) i;
369 NKern::RestoreInterrupts(irq);
371 __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
375 void TTemplateDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
377 // Unlink the last item in the h/w descriptor chain from a subsequent chain that it was
378 // possibly linked to.
381 __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::UnlinkHwDes"));
382 TDmaDesc* pD = HdrToHwDes(aHdr);
383 pD->iDescAddr = TDmaDesc::KStopBitMask;
385 // TO DO: Modify pD->iCmd so that an end-of-transfer interrupt will get raised.
390 void TTemplateDmac::Isr(TAny* aThis)
392 // This ISR reads the interrupt identification and calls back into the base class
393 // interrupt service handler with the channel identifier and an indication whether the
394 // transfer completed correctly or with an error.
397 TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
399 // TO DO: Implement the behaviour described above, call HandleIsr().
401 HandleIsr(me.iChannels[5], EDmaCallbackRequestCompletion, ETrue); // Example
406 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr)
408 // Changes return type of base class call.
411 return static_cast<TDmaDesc*>(TDmac::HdrToHwDes(aHdr));
415 //////////////////////////////////////////////////////////////////////////////
416 // Channel Opening/Closing (Channel Allocator)
417 //////////////////////////////////////////////////////////////////////////////
419 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/)
424 __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
426 __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
428 TDmaChannel* pC = Controller.iChannels + aOpenId;
435 pC->iController = &Controller;
436 pC->iPslId = aOpenId;
443 void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
452 TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
457 return KErrNotSupported;
461 //////////////////////////////////////////////////////////////////////////////
462 // DLL Exported Function
463 //////////////////////////////////////////////////////////////////////////////
465 DECLARE_STANDARD_EXTENSION()
467 // Creates and initializes a new DMA controller object on the kernel heap.
470 __KTRACE_OPT2(KBOOT, KDMA, Kern::Printf("Starting DMA Extension"));
472 const TInt r = DmaChannelMgr::Initialise();
477 return Controller.Create();