bsptemplate/asspandvariant/template_assp/dmapsl.cpp
changeset 9 96e5fb8b040d
child 8 538db54a451d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // template\template_assp\dmapsl.cpp
       
    15 // Template DMA Platform Specific Layer (PSL).
       
    16 // 
       
    17 //
       
    18 
       
    19 
       
    20 #include <kernel/kern_priv.h>
       
    21 #include <template_assp.h>									// /assp/template_assp/
       
    22 #include <drivers/dma.h>
       
    23 
       
    24 // Debug support
       
    25 static const char KDmaPanicCat[] = "DMA PSL";
       
    26 
       
    27 static const TInt KMaxTransferLen = 0x1FE0;					// max transfer length for this DMAC
       
    28 static const TInt KMemAlignMask = 7;				  // memory addresses passed to DMAC must be multiple of 8
       
    29 static const TInt KChannelCount = 16;						// we got 16 channels
       
    30 static const TInt KDesCount = 1024;							// DMA descriptor count
       
    31 
       
    32 
       
    33 class TDmaDesc
       
    34 //
       
    35 // Hardware DMA descriptor
       
    36 //
       
    37 	{
       
    38 public:
       
    39 	enum {KStopBitMask = 1};
       
    40 public:
       
    41 	TPhysAddr iDescAddr;
       
    42 	TPhysAddr iSrcAddr;
       
    43 	TPhysAddr iDestAddr;
       
    44 	TUint32 iCmd;
       
    45 	};
       
    46 
       
    47 
       
    48 //////////////////////////////////////////////////////////////////////////////
       
    49 // Test Support
       
    50 //////////////////////////////////////////////////////////////////////////////
       
    51 
       
    52 TDmaTestInfo TestInfo =
       
    53 	{
       
    54 	0,
       
    55 	0,
       
    56 	0,
       
    57 	0,
       
    58 	NULL,
       
    59 	0,
       
    60 	NULL,
       
    61 	0,
       
    62 	NULL
       
    63 	};
       
    64 
       
    65 
       
    66 EXPORT_C const TDmaTestInfo& DmaTestInfo()
       
    67 //
       
    68 //
       
    69 //
       
    70 	{
       
    71 	return TestInfo;
       
    72 	}
       
    73 
       
    74 
       
    75 //////////////////////////////////////////////////////////////////////////////
       
    76 // Helper Functions
       
    77 //////////////////////////////////////////////////////////////////////////////
       
    78 
       
    79 inline TBool IsHwDesAligned(TAny* aDes)
       
    80 //
       
    81 // Checks whether given hardware descriptor is 16-bytes aligned.
       
    82 //
       
    83 	{
       
    84 	return ((TLinAddr)aDes & 0xF) == 0;
       
    85 	}
       
    86 
       
    87 
       
    88 static TUint32 DcmdReg(TInt aCount, TUint aFlags, TUint32 aPslInfo)
       
    89 //
       
    90 // Returns value to set in DMA command register or in descriptor command field.
       
    91 //
       
    92 	{
       
    93 	// TO DO: Construct CMD word from input values.
       
    94 	// The return value should reflect the actual control word.
       
    95 	return (aCount | aFlags | aPslInfo);
       
    96 	}
       
    97 
       
    98 
       
    99 //////////////////////////////////////////////////////////////////////////////
       
   100 // Derived Channel (Scatter/Gather)
       
   101 //////////////////////////////////////////////////////////////////////////////
       
   102 
       
   103 class TTemplateSgChannel : public TDmaSgChannel
       
   104 	{
       
   105 public:
       
   106 	TDmaDesc* iTmpDes;
       
   107 	TPhysAddr iTmpDesPhysAddr;
       
   108 	};
       
   109 
       
   110 
       
   111 //////////////////////////////////////////////////////////////////////////////
       
   112 // Derived Controller Class
       
   113 //////////////////////////////////////////////////////////////////////////////
       
   114 
       
   115 class TTemplateDmac : public TDmac
       
   116 	{
       
   117 public:
       
   118 	TTemplateDmac();
       
   119 	TInt Create();
       
   120 private:
       
   121 	// from TDmac (PIL pure virtual)
       
   122 	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
       
   123 	virtual void StopTransfer(const TDmaChannel& aChannel);
       
   124 	virtual TBool IsIdle(const TDmaChannel& aChannel);
       
   125 	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
       
   126 	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
       
   127 	// from TDmac (PIL virtual)
       
   128 	virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
   129  						   TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
       
   130 	virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
       
   131 	virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
       
   132 							 const SDmaDesHdr& aNewHdr);
       
   133 	virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
       
   134 	// other
       
   135 	static void Isr(TAny* aThis);
       
   136 	inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
       
   137 private:
       
   138 	static const SCreateInfo KInfo;
       
   139 public:
       
   140 	TTemplateSgChannel iChannels[KChannelCount];
       
   141 	};
       
   142 
       
   143 static TTemplateDmac Controller;
       
   144 
       
   145 const TDmac::SCreateInfo TTemplateDmac::KInfo =
       
   146 	{
       
   147 	KChannelCount,
       
   148 	KDesCount,
       
   149 	TDmac::KCapsBitHwDes,
       
   150 	sizeof(TDmaDesc),
       
   151 	EMapAttrSupRw | EMapAttrFullyBlocking
       
   152 	};
       
   153 
       
   154 
       
   155 TTemplateDmac::TTemplateDmac()
       
   156 //
       
   157 // Constructor.
       
   158 //
       
   159 	: TDmac(KInfo)
       
   160 	{}
       
   161 
       
   162 
       
   163 TInt TTemplateDmac::Create()
       
   164 //
       
   165 // Second phase construction.
       
   166 //
       
   167 	{
       
   168 	TInt r = TDmac::Create(KInfo);							// Base class Create()
       
   169 	if (r == KErrNone)
       
   170 		{
       
   171 		__DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
       
   172 		for (TInt i=0; i < KChannelCount; ++i)
       
   173 			{
       
   174 			TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
       
   175 			iChannels[i].iTmpDes = pD;
       
   176 			iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD);
       
   177 			iFreeHdr = iFreeHdr->iNext;
       
   178 			}
       
   179 		r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
       
   180 		if (r == KErrNone)
       
   181 			{
       
   182 			// TO DO: Map DMA clients (requests) to DMA channels here.
       
   183 
       
   184 			r = Interrupt::Enable(EAsspIntIdDma);
       
   185 			}
       
   186 		}
       
   187 	return r;
       
   188 	}
       
   189 
       
   190 
       
   191 void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
       
   192 //
       
   193 // Initiates a (previously constructed) request on a specific channel.
       
   194 //
       
   195 	{
       
   196 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   197 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   198 
       
   199 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
       
   200 
       
   201 	// TO DO (for instance): Load the first descriptor address into the DMAC and start it
       
   202 	// by setting the RUN bit.
       
   203 	(void) *pD, (void) i;
       
   204 
       
   205 	}
       
   206 
       
   207 
       
   208 void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
       
   209 //
       
   210 // Stops a running channel.
       
   211 //
       
   212 	{
       
   213 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   214 
       
   215 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
       
   216 
       
   217 	// TO DO (for instance): Clear the RUN bit of the channel.
       
   218 	(void) i;
       
   219 
       
   220 	}
       
   221 
       
   222 
       
   223 TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
       
   224 //
       
   225 // Returns the state of a given channel.
       
   226 //
       
   227 	{
       
   228 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   229 
       
   230 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
       
   231 
       
   232 	// TO DO (for instance): Return the state of the RUN bit of the channel.
       
   233 	// The return value should reflect the actual state.
       
   234 	(void) i;
       
   235 
       
   236 	return ETrue;
       
   237 	}
       
   238 
       
   239 
       
   240 TInt TTemplateDmac::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
       
   241 //
       
   242 // Returns the maximum transfer size for a given transfer.
       
   243 //
       
   244 	{
       
   245 	// TO DO: Determine the proper return value, based on the arguments.
       
   246 
       
   247 	// For instance:
       
   248 	return KMaxTransferLen;
       
   249 	}
       
   250 
       
   251 
       
   252 TUint TTemplateDmac::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
       
   253 //
       
   254 // Returns the memory buffer alignment restrictions mask for a given transfer.
       
   255 //
       
   256 	{
       
   257 	// TO DO: Determine the proper return value, based on the arguments.
       
   258 
       
   259 	// For instance:
       
   260 	return KMemAlignMask;
       
   261 	}
       
   262 
       
   263 
       
   264 void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
       
   265 							  TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/)
       
   266 //
       
   267 // Sets up (from a passed in request) the descriptor with that fragment's source and destination address,
       
   268 // the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral,
       
   269 // burst size, transfer width).
       
   270 //
       
   271 	{
       
   272 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   273 
       
   274 	__KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
       
   275 
       
   276 	// Unaligned descriptor? Bug in generic layer!
       
   277 	__DMA_ASSERTD(IsHwDesAligned(pD));
       
   278 
       
   279 	pD->iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc);
       
   280 	pD->iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest);
       
   281 	pD->iCmd = DcmdReg(aCount, aFlags, aPslInfo);
       
   282 	pD->iDescAddr = TDmaDesc::KStopBitMask;
       
   283 	}
       
   284 
       
   285 
       
   286 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
       
   287 //
       
   288 // Chains hardware descriptors together by setting the next pointer of the original descriptor
       
   289 // to the physical address of the descriptor to be chained.
       
   290 //
       
   291 	{
       
   292 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   293 	TDmaDesc* pN = HdrToHwDes(aNextHdr);
       
   294 
       
   295 	__KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
       
   296 
       
   297 	// Unaligned descriptor? Bug in generic layer!
       
   298 	__DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
       
   299 
       
   300 	// TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
       
   301 
       
   302 	pD->iDescAddr = DesLinToPhys(pN);
       
   303 	}
       
   304 
       
   305 
       
   306 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
       
   307 								const SDmaDesHdr& aNewHdr)
       
   308 //
       
   309 // Appends a descriptor to the chain while the channel is running.
       
   310 //
       
   311 	{
       
   312 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   313 
       
   314 	TDmaDesc* pL = HdrToHwDes(aLastHdr);
       
   315 	TDmaDesc* pN = HdrToHwDes(aNewHdr);
       
   316 
       
   317 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
       
   318 									i, pL, pN));
       
   319 	// Unaligned descriptor? Bug in generic layer!
       
   320 	__DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
       
   321 
       
   322 	TPhysAddr newPhys = DesLinToPhys(pN);
       
   323 
       
   324 	const TInt irq = NKern::DisableAllInterrupts();
       
   325 	StopTransfer(aChannel);
       
   326 
       
   327 	pL->iDescAddr = newPhys;
       
   328 	const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
       
   329 	TDmaDesc* pD = channel.iTmpDes;
       
   330 
       
   331 	// TO DO: Implement the appropriate algorithm for appending a descriptor here.
       
   332 	(void) *pD, (void) i;
       
   333 
       
   334 	NKern::RestoreInterrupts(irq);
       
   335 
       
   336 	__KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
       
   337 	}
       
   338 
       
   339 
       
   340 void TTemplateDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
       
   341 //
       
   342 // Unlink the last item in the h/w descriptor chain from a subsequent chain that it was
       
   343 // possibly linked to.
       
   344 //
       
   345 	{
       
   346  	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::UnlinkHwDes"));
       
   347   	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   348   	pD->iDescAddr = TDmaDesc::KStopBitMask;
       
   349 
       
   350 	// TO DO: Modify pD->iCmd so that an end-of-transfer interrupt will get raised.
       
   351 
       
   352 	}
       
   353 
       
   354 
       
   355 void TTemplateDmac::Isr(TAny* aThis)
       
   356 //
       
   357 // This ISR reads the interrupt identification and calls back into the base class
       
   358 // interrupt service handler with the channel identifier and an indication whether the
       
   359 // transfer completed correctly or with an error.
       
   360 //
       
   361 	{
       
   362 	TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
       
   363 
       
   364 	// TO DO: Implement the behaviour described above, call HandleIsr().
       
   365 
       
   366 	HandleIsr(me.iChannels[5], 0);							// Example
       
   367 
       
   368 	}
       
   369 
       
   370 
       
   371 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr)
       
   372 //
       
   373 // Changes return type of base class call.
       
   374 //
       
   375 	{
       
   376 	return static_cast<TDmaDesc*>(TDmac::HdrToHwDes(aHdr));
       
   377 	}
       
   378 
       
   379 
       
   380 //////////////////////////////////////////////////////////////////////////////
       
   381 // Channel Opening/Closing (Channel Allocator)
       
   382 //////////////////////////////////////////////////////////////////////////////
       
   383 
       
   384 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
       
   385 //
       
   386 //
       
   387 //
       
   388 	{
       
   389 	__KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
       
   390 
       
   391 	__DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
       
   392 
       
   393 	TDmaChannel* pC = Controller.iChannels + aOpenId;
       
   394 	if (pC->IsOpened())
       
   395 		pC = NULL;
       
   396 	else
       
   397 		{
       
   398 		pC->iController = &Controller;
       
   399 		pC->iPslId = aOpenId;
       
   400 		}
       
   401 
       
   402 	return pC;
       
   403 	}
       
   404 
       
   405 
       
   406 void DmaChannelMgr::Close(TDmaChannel* /* aChannel */)
       
   407 //
       
   408 //
       
   409 //
       
   410 	{
       
   411 	// NOP
       
   412 	}
       
   413 
       
   414 
       
   415 TInt DmaChannelMgr::StaticExtension(TInt /* aCmd */, TAny* /* aArg */)
       
   416 //
       
   417 //
       
   418 //
       
   419 	{
       
   420 	return KErrNotSupported;
       
   421 	}
       
   422 
       
   423 
       
   424 //////////////////////////////////////////////////////////////////////////////
       
   425 // DLL Exported Function
       
   426 //////////////////////////////////////////////////////////////////////////////
       
   427 
       
   428 DECLARE_STANDARD_EXTENSION()
       
   429 //
       
   430 // Creates and initializes a new DMA controller object on the kernel heap.
       
   431 //
       
   432 	{
       
   433 	__KTRACE_OPT2(KBOOT, KDMA, Kern::Printf("Starting DMA Extension"));
       
   434 
       
   435 	return Controller.Create();
       
   436 	}