1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/bsptemplate/asspandvariant/template_assp/dmapsl.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,478 @@
1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// bsptemplate/asspvariant/template_assp/dmapsl.cpp
1.18 +// Template DMA Platform Specific Layer (PSL).
1.19 +//
1.20 +//
1.21 +
1.22 +
1.23 +#include <kernel/kern_priv.h>
1.24 +#include <template_assp.h> // /assp/template_assp/
1.25 +
1.26 +#include <drivers/dma.h>
1.27 +#include <drivers/dma_hai.h>
1.28 +
1.29 +
1.30 +// Debug support
1.31 +static const char KDmaPanicCat[] = "DMA PSL - " __FILE__;
1.32 +
1.33 +static const TInt KMaxTransferLen = 0x1FE0; // max transfer length for this DMAC
1.34 +static const TInt KMemAlignMask = 7; // memory addresses passed to DMAC must be multiple of 8
1.35 +static const TInt KChannelCount = 16; // we got 16 channels
1.36 +static const TInt KDesCount = 160; // Initial DMA descriptor count
1.37 +
1.38 +
1.39 +class TDmaDesc
1.40 +//
1.41 +// Hardware DMA descriptor
1.42 +//
1.43 + {
1.44 +public:
1.45 + enum {KStopBitMask = 1};
1.46 +public:
1.47 + TPhysAddr iDescAddr;
1.48 + TPhysAddr iSrcAddr;
1.49 + TPhysAddr iDestAddr;
1.50 + TUint32 iCmd;
1.51 + };
1.52 +
1.53 +
1.54 +//////////////////////////////////////////////////////////////////////////////
1.55 +// Test Support
1.56 +//////////////////////////////////////////////////////////////////////////////
1.57 +
1.58 +/**
1.59 +TO DO: Fill in to provide information to the V1 test harness (t_dma.exe)
1.60 +*/
1.61 +TDmaTestInfo TestInfo =
1.62 + {
1.63 + 0,
1.64 + 0,
1.65 + 0,
1.66 + 0,
1.67 + NULL,
1.68 + 0,
1.69 + NULL,
1.70 + 0,
1.71 + NULL
1.72 + };
1.73 +
1.74 +
1.75 +EXPORT_C const TDmaTestInfo& DmaTestInfo()
1.76 +//
1.77 +//
1.78 +//
1.79 + {
1.80 + return TestInfo;
1.81 + }
1.82 +
1.83 +/**
1.84 +TO DO: Fill in to provide information to the V2 test harness (t_dma2.exe)
1.85 +*/
1.86 +TDmaV2TestInfo TestInfov2 =
1.87 + {
1.88 + 0,
1.89 + 0,
1.90 + 0,
1.91 + 0,
1.92 + {0},
1.93 + 0,
1.94 + {0},
1.95 + 0,
1.96 + {0}
1.97 + };
1.98 +
1.99 +EXPORT_C const TDmaV2TestInfo& DmaTestInfoV2()
1.100 + {
1.101 + return TestInfov2;
1.102 + }
1.103 +
1.104 +//////////////////////////////////////////////////////////////////////////////
1.105 +// Helper Functions
1.106 +//////////////////////////////////////////////////////////////////////////////
1.107 +
1.108 +inline TBool IsHwDesAligned(TAny* aDes)
1.109 +//
1.110 +// Checks whether given hardware descriptor is 16-bytes aligned.
1.111 +//
1.112 + {
1.113 + return ((TLinAddr)aDes & 0xF) == 0;
1.114 + }
1.115 +
1.116 +
1.117 +static TUint32 DmaCmdReg(TUint aCount, TUint aFlags, TUint32 aSrcPslInfo, TUint32 aDstPslInfo)
1.118 +//
1.119 +// Returns value to set in DMA command register or in descriptor command field.
1.120 +//
1.121 + {
1.122 + // TO DO: Construct CMD word from input values.
1.123 + // The return value should reflect the actual control word.
1.124 + return (aCount | aFlags | aSrcPslInfo | aDstPslInfo);
1.125 + }
1.126 +
1.127 +
1.128 +//////////////////////////////////////////////////////////////////////////////
1.129 +// Derived Channel (Scatter/Gather)
1.130 +//////////////////////////////////////////////////////////////////////////////
1.131 +
1.132 +class TTemplateSgChannel : public TDmaSgChannel
1.133 + {
1.134 +public:
1.135 + TDmaDesc* iTmpDes;
1.136 + TPhysAddr iTmpDesPhysAddr;
1.137 + };
1.138 +
1.139 +
1.140 +//////////////////////////////////////////////////////////////////////////////
1.141 +// Derived Controller Class
1.142 +//////////////////////////////////////////////////////////////////////////////
1.143 +
1.144 +class TTemplateDmac : public TDmac
1.145 + {
1.146 +public:
1.147 + TTemplateDmac();
1.148 + TInt Create();
1.149 +private:
1.150 + // from TDmac (PIL pure virtual)
1.151 + virtual void StopTransfer(const TDmaChannel& aChannel);
1.152 + virtual TBool IsIdle(const TDmaChannel& aChannel);
1.153 + virtual TUint MaxTransferLength(TDmaChannel& aChannel, TUint aSrcFlags,
1.154 + TUint aDstFlags, TUint32 aPslInfo);
1.155 + virtual TUint AddressAlignMask(TDmaChannel& aChannel, TUint aSrcFlags,
1.156 + TUint aDstFlags, TUint32 aPslInfo);
1.157 + // from TDmac (PIL virtual)
1.158 + virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
1.159 + virtual TInt InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs);
1.160 + virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
1.161 + virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
1.162 + const SDmaDesHdr& aNewHdr);
1.163 + virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
1.164 + // other
1.165 + static void Isr(TAny* aThis);
1.166 + inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
1.167 +private:
1.168 + static const SCreateInfo KInfo;
1.169 +public:
1.170 + TTemplateSgChannel iChannels[KChannelCount];
1.171 + };
1.172 +
1.173 +
1.174 +static TTemplateDmac Controller;
1.175 +
1.176 +
1.177 +const TDmac::SCreateInfo TTemplateDmac::KInfo =
1.178 + {
1.179 + ETrue, // iCapsHwDes
1.180 + KDesCount, // iDesCount
1.181 + sizeof(TDmaDesc), // iDesSize
1.182 + EMapAttrSupRw | EMapAttrFullyBlocking // iDesChunkAttribs
1.183 + };
1.184 +
1.185 +
1.186 +TTemplateDmac::TTemplateDmac()
1.187 +//
1.188 +// Constructor.
1.189 +//
1.190 + : TDmac(KInfo)
1.191 + {}
1.192 +
1.193 +
1.194 +TInt TTemplateDmac::Create()
1.195 +//
1.196 +// Second phase construction.
1.197 +//
1.198 + {
1.199 + TInt r = TDmac::Create(KInfo); // Base class Create()
1.200 + if (r == KErrNone)
1.201 + {
1.202 + __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
1.203 + for (TInt i=0; i < KChannelCount; ++i)
1.204 + {
1.205 + TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
1.206 + iChannels[i].iTmpDes = pD;
1.207 + iChannels[i].iTmpDesPhysAddr = HwDesLinToPhys(pD);
1.208 + iFreeHdr = iFreeHdr->iNext;
1.209 + }
1.210 + r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
1.211 + if (r == KErrNone)
1.212 + {
1.213 + // TO DO: Map DMA clients (requests) to DMA channels here.
1.214 +
1.215 + r = Interrupt::Enable(EAsspIntIdDma);
1.216 + }
1.217 + }
1.218 + return r;
1.219 + }
1.220 +
1.221 +
1.222 +void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
1.223 +//
1.224 +// Initiates a (previously constructed) request on a specific channel.
1.225 +//
1.226 + {
1.227 + const TUint8 i = static_cast<TUint8>(aChannel.PslId());
1.228 + TDmaDesc* pD = HdrToHwDes(aHdr);
1.229 +
1.230 + __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
1.231 +
1.232 + // TO DO (for instance): Load the first descriptor address into the DMAC and start it
1.233 + // by setting the RUN bit.
1.234 + (void) *pD, (void) i;
1.235 +
1.236 + }
1.237 +
1.238 +
1.239 +void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
1.240 +//
1.241 +// Stops a running channel.
1.242 +//
1.243 + {
1.244 + const TUint8 i = static_cast<TUint8>(aChannel.PslId());
1.245 +
1.246 + __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
1.247 +
1.248 + // TO DO (for instance): Clear the RUN bit of the channel.
1.249 + (void) i;
1.250 +
1.251 + }
1.252 +
1.253 +
1.254 +TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
1.255 +//
1.256 +// Returns the state of a given channel.
1.257 +//
1.258 + {
1.259 + const TUint8 i = static_cast<TUint8>(aChannel.PslId());
1.260 +
1.261 + __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
1.262 +
1.263 + // TO DO (for instance): Return the state of the RUN bit of the channel.
1.264 + // The return value should reflect the actual state.
1.265 + (void) i;
1.266 +
1.267 + return ETrue;
1.268 + }
1.269 +
1.270 +
1.271 +TUint TTemplateDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/,
1.272 + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
1.273 +//
1.274 +// Returns the maximum transfer length in bytes for a given transfer.
1.275 +//
1.276 + {
1.277 + // TO DO: Determine the proper return value, based on the arguments.
1.278 +
1.279 + // For instance:
1.280 + return KMaxTransferLen;
1.281 + }
1.282 +
1.283 +
1.284 +TUint TTemplateDmac::AddressAlignMask(TDmaChannel& aChannel, TUint /*aSrcFlags*/,
1.285 + TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
1.286 +//
1.287 +// Returns the memory buffer alignment restrictions mask for a given transfer.
1.288 +//
1.289 + {
1.290 + // TO DO: Determine the proper return value, based on the arguments.
1.291 +
1.292 + // For instance:
1.293 + return KMemAlignMask;
1.294 + }
1.295 +
1.296 +
1.297 +TInt TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs)
1.298 +//
1.299 +// Sets up (from a passed in request) the descriptor with that fragment's
1.300 +// source and destination address, the fragment size, and the (driver/DMA
1.301 +// controller) specific transfer parameters (mem/peripheral, burst size,
1.302 +// transfer width).
1.303 +//
1.304 + {
1.305 + TDmaDesc* pD = HdrToHwDes(aHdr);
1.306 +
1.307 + __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
1.308 +
1.309 + // Unaligned descriptor? Bug in generic layer!
1.310 + __DMA_ASSERTD(IsHwDesAligned(pD));
1.311 +
1.312 + const TDmaTransferConfig& src = aTransferArgs.iSrcConfig;
1.313 + const TDmaTransferConfig& dst = aTransferArgs.iDstConfig;
1.314 + pD->iSrcAddr = (src.iFlags & KDmaPhysAddr) ? src.iAddr : Epoc::LinearToPhysical(src.iAddr);
1.315 + pD->iDestAddr = (dst.iFlags & KDmaPhysAddr) ? dst.iAddr : Epoc::LinearToPhysical(dst.iAddr);
1.316 + pD->iCmd = DmaCmdReg(aTransferArgs.iTransferCount, aTransferArgs.iFlags,
1.317 + src.iPslTargetInfo, dst.iPslTargetInfo);
1.318 + pD->iDescAddr = TDmaDesc::KStopBitMask;
1.319 +
1.320 + return KErrNone;
1.321 + }
1.322 +
1.323 +
1.324 +void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
1.325 +//
1.326 +// Chains hardware descriptors together by setting the next pointer of the original descriptor
1.327 +// to the physical address of the descriptor to be chained.
1.328 +//
1.329 + {
1.330 + TDmaDesc* pD = HdrToHwDes(aHdr);
1.331 + TDmaDesc* pN = HdrToHwDes(aNextHdr);
1.332 +
1.333 + __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
1.334 +
1.335 + // Unaligned descriptor? Bug in generic layer!
1.336 + __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
1.337 +
1.338 + // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
1.339 +
1.340 + pD->iDescAddr = HwDesLinToPhys(pN);
1.341 + }
1.342 +
1.343 +
1.344 +void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
1.345 + const SDmaDesHdr& aNewHdr)
1.346 +//
1.347 +// Appends a descriptor to the chain while the channel is running.
1.348 +//
1.349 + {
1.350 + const TUint8 i = static_cast<TUint8>(aChannel.PslId());
1.351 +
1.352 + TDmaDesc* pL = HdrToHwDes(aLastHdr);
1.353 + TDmaDesc* pN = HdrToHwDes(aNewHdr);
1.354 +
1.355 + __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
1.356 + i, pL, pN));
1.357 + // Unaligned descriptor? Bug in generic layer!
1.358 + __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
1.359 +
1.360 + TPhysAddr newPhys = HwDesLinToPhys(pN);
1.361 +
1.362 + const TInt irq = NKern::DisableAllInterrupts();
1.363 + StopTransfer(aChannel);
1.364 +
1.365 + pL->iDescAddr = newPhys;
1.366 + const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
1.367 + TDmaDesc* pD = channel.iTmpDes;
1.368 +
1.369 + // TO DO: Implement the appropriate algorithm for appending a descriptor here.
1.370 + (void) *pD, (void) i;
1.371 +
1.372 + NKern::RestoreInterrupts(irq);
1.373 +
1.374 + __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
1.375 + }
1.376 +
1.377 +
1.378 +void TTemplateDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
1.379 +//
1.380 +// Unlink the last item in the h/w descriptor chain from a subsequent chain that it was
1.381 +// possibly linked to.
1.382 +//
1.383 + {
1.384 + __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::UnlinkHwDes"));
1.385 + TDmaDesc* pD = HdrToHwDes(aHdr);
1.386 + pD->iDescAddr = TDmaDesc::KStopBitMask;
1.387 +
1.388 + // TO DO: Modify pD->iCmd so that an end-of-transfer interrupt will get raised.
1.389 +
1.390 + }
1.391 +
1.392 +
1.393 +void TTemplateDmac::Isr(TAny* aThis)
1.394 +//
1.395 +// This ISR reads the interrupt identification and calls back into the base class
1.396 +// interrupt service handler with the channel identifier and an indication whether the
1.397 +// transfer completed correctly or with an error.
1.398 +//
1.399 + {
1.400 + TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
1.401 +
1.402 + // TO DO: Implement the behaviour described above, call HandleIsr().
1.403 +
1.404 + HandleIsr(me.iChannels[5], EDmaCallbackRequestCompletion, ETrue); // Example
1.405 +
1.406 + }
1.407 +
1.408 +
1.409 +inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr)
1.410 +//
1.411 +// Changes return type of base class call.
1.412 +//
1.413 + {
1.414 + return static_cast<TDmaDesc*>(TDmac::HdrToHwDes(aHdr));
1.415 + }
1.416 +
1.417 +
1.418 +//////////////////////////////////////////////////////////////////////////////
1.419 +// Channel Opening/Closing (Channel Allocator)
1.420 +//////////////////////////////////////////////////////////////////////////////
1.421 +
1.422 +TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/)
1.423 +//
1.424 +//
1.425 +//
1.426 + {
1.427 + __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
1.428 +
1.429 + __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
1.430 +
1.431 + TDmaChannel* pC = Controller.iChannels + aOpenId;
1.432 + if (pC->IsOpened())
1.433 + {
1.434 + pC = NULL;
1.435 + }
1.436 + else
1.437 + {
1.438 + pC->iController = &Controller;
1.439 + pC->iPslId = aOpenId;
1.440 + }
1.441 +
1.442 + return pC;
1.443 + }
1.444 +
1.445 +
1.446 +void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
1.447 +//
1.448 +//
1.449 +//
1.450 + {
1.451 + // NOP
1.452 + }
1.453 +
1.454 +
1.455 +TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
1.456 +//
1.457 +//
1.458 +//
1.459 + {
1.460 + return KErrNotSupported;
1.461 + }
1.462 +
1.463 +
1.464 +//////////////////////////////////////////////////////////////////////////////
1.465 +// DLL Exported Function
1.466 +//////////////////////////////////////////////////////////////////////////////
1.467 +
1.468 +DECLARE_STANDARD_EXTENSION()
1.469 +//
1.470 +// Creates and initializes a new DMA controller object on the kernel heap.
1.471 +//
1.472 + {
1.473 + __KTRACE_OPT2(KBOOT, KDMA, Kern::Printf("Starting DMA Extension"));
1.474 +
1.475 + const TInt r = DmaChannelMgr::Initialise();
1.476 + if (r != KErrNone)
1.477 + {
1.478 + return r;
1.479 + }
1.480 + return Controller.Create();
1.481 + }