bsptemplate/asspandvariant/template_assp/dmapsl_v2.cpp
changeset 139 95f71bcdcdb7
equal deleted inserted replaced
109:b3a1d9898418 139:95f71bcdcdb7
       
     1 // Copyright (c) 2004-2010 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 // bsptemplate/asspvariant/template_assp/dmapsl_v2.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 
       
    23 #include <drivers/dma.h>
       
    24 #include <drivers/dma_hai.h>
       
    25 
       
    26 
       
    27 // Debug support
       
    28 static const char KDmaPanicCat[] = "DMA PSL - " __FILE__;
       
    29 
       
    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
       
    34 
       
    35 
       
    36 class TDmaDesc
       
    37 //
       
    38 // Hardware DMA descriptor
       
    39 //
       
    40 	{
       
    41 public:
       
    42 	enum {KStopBitMask = 1};
       
    43 public:
       
    44 	TPhysAddr iDescAddr;
       
    45 	TPhysAddr iSrcAddr;
       
    46 	TPhysAddr iDestAddr;
       
    47 	TUint32 iCmd;
       
    48 	};
       
    49 
       
    50 
       
    51 //////////////////////////////////////////////////////////////////////////////
       
    52 // Test Support
       
    53 //////////////////////////////////////////////////////////////////////////////
       
    54 
       
    55 /**
       
    56 TO DO: Fill in to provide information to the V1 test harness (t_dma.exe)
       
    57 */
       
    58 TDmaTestInfo TestInfo =
       
    59 	{
       
    60 	0,
       
    61 	0,
       
    62 	0,
       
    63 	0,
       
    64 	NULL,
       
    65 	0,
       
    66 	NULL,
       
    67 	0,
       
    68 	NULL
       
    69 	};
       
    70 
       
    71 
       
    72 EXPORT_C const TDmaTestInfo& DmaTestInfo()
       
    73 //
       
    74 //
       
    75 //
       
    76 	{
       
    77 	return TestInfo;
       
    78 	}
       
    79 
       
    80 /**
       
    81 TO DO: Fill in to provide information to the V2 test harness (t_dma2.exe)
       
    82 */
       
    83 TDmaV2TestInfo TestInfov2 =
       
    84 	{
       
    85 	0,
       
    86 	0,
       
    87 	0,
       
    88 	0,
       
    89 	{0},
       
    90 	0,
       
    91 	{0},
       
    92 	0,
       
    93 	{0}
       
    94 	};
       
    95 
       
    96 EXPORT_C const TDmaV2TestInfo& DmaTestInfoV2()
       
    97 	{
       
    98 	return TestInfov2;
       
    99 	}
       
   100 
       
   101 //////////////////////////////////////////////////////////////////////////////
       
   102 // Helper Functions
       
   103 //////////////////////////////////////////////////////////////////////////////
       
   104 
       
   105 inline TBool IsHwDesAligned(TAny* aDes)
       
   106 //
       
   107 // Checks whether given hardware descriptor is 16-bytes aligned.
       
   108 //
       
   109 	{
       
   110 	return ((TLinAddr)aDes & 0xF) == 0;
       
   111 	}
       
   112 
       
   113 
       
   114 static TUint32 DmaCmdReg(TUint aCount, TUint aFlags, TUint32 aSrcPslInfo, TUint32 aDstPslInfo)
       
   115 //
       
   116 // Returns value to set in DMA command register or in descriptor command field.
       
   117 //
       
   118 	{
       
   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);
       
   122 	}
       
   123 
       
   124 
       
   125 //////////////////////////////////////////////////////////////////////////////
       
   126 // Derived Channel (Scatter/Gather)
       
   127 //////////////////////////////////////////////////////////////////////////////
       
   128 
       
   129 class TTemplateSgChannel : public TDmaSgChannel
       
   130 	{
       
   131 public:
       
   132 	TDmaDesc* iTmpDes;
       
   133 	TPhysAddr iTmpDesPhysAddr;
       
   134 	};
       
   135 
       
   136 
       
   137 //////////////////////////////////////////////////////////////////////////////
       
   138 // Derived Controller Class
       
   139 //////////////////////////////////////////////////////////////////////////////
       
   140 
       
   141 class TTemplateDmac : public TDmac
       
   142 	{
       
   143 public:
       
   144 	TTemplateDmac();
       
   145 	TInt Create();
       
   146 private:
       
   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);
       
   161 	// other
       
   162 	static void Isr(TAny* aThis);
       
   163 	inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);
       
   164 private:
       
   165 	static const SCreateInfo KInfo;
       
   166 public:
       
   167 	TTemplateSgChannel iChannels[KChannelCount];
       
   168 	};
       
   169 
       
   170 
       
   171 static TTemplateDmac Controller;
       
   172 
       
   173 
       
   174 const TDmac::SCreateInfo TTemplateDmac::KInfo =
       
   175 	{
       
   176 	ETrue,													// iCapsHwDes
       
   177 	KDesCount,												// iDesCount
       
   178 	sizeof(TDmaDesc),										// iDesSize
       
   179 	EMapAttrSupRw | EMapAttrFullyBlocking					// iDesChunkAttribs
       
   180 	};
       
   181 
       
   182 
       
   183 TTemplateDmac::TTemplateDmac()
       
   184 //
       
   185 // Constructor.
       
   186 //
       
   187 	: TDmac(KInfo)
       
   188 	{}
       
   189 
       
   190 
       
   191 TInt TTemplateDmac::Create()
       
   192 //
       
   193 // Second phase construction.
       
   194 //
       
   195 	{
       
   196 	TInt r = TDmac::Create(KInfo);							// Base class Create()
       
   197 	if (r == KErrNone)
       
   198 		{
       
   199 		__DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone);
       
   200 		for (TInt i=0; i < KChannelCount; ++i)
       
   201 			{
       
   202 			TDmaDesc* pD = HdrToHwDes(*iFreeHdr);
       
   203 			iChannels[i].iTmpDes = pD;
       
   204 			iChannels[i].iTmpDesPhysAddr = HwDesLinToPhys(pD);
       
   205 			iFreeHdr = iFreeHdr->iNext;
       
   206 			}
       
   207 		r = Interrupt::Bind(EAsspIntIdDma, Isr, this);
       
   208 		if (r == KErrNone)
       
   209 			{
       
   210 			// TO DO: Map DMA clients (requests) to DMA channels here.
       
   211 
       
   212 			r = Interrupt::Enable(EAsspIntIdDma);
       
   213 			}
       
   214 		}
       
   215 	return r;
       
   216 	}
       
   217 
       
   218 
       
   219 void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
       
   220 //
       
   221 // Initiates a (previously constructed) request on a specific channel.
       
   222 //
       
   223 	{
       
   224 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   225 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   226 
       
   227 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
       
   228 
       
   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;
       
   232 
       
   233 	}
       
   234 
       
   235 
       
   236 void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)
       
   237 //
       
   238 // Stops a running channel.
       
   239 //
       
   240 	{
       
   241 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   242 
       
   243 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i));
       
   244 
       
   245 	// TO DO (for instance): Clear the RUN bit of the channel.
       
   246 	(void) i;
       
   247 
       
   248 	}
       
   249 
       
   250 
       
   251 TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
       
   252 //
       
   253 // Returns the state of a given channel.
       
   254 //
       
   255 	{
       
   256 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   257 
       
   258 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::IsIdle channel=%d", i));
       
   259 
       
   260 	// TO DO (for instance): Return the state of the RUN bit of the channel.
       
   261 	// The return value should reflect the actual state.
       
   262 	(void) i;
       
   263 
       
   264 	return ETrue;
       
   265 	}
       
   266 
       
   267 
       
   268 TUint TTemplateDmac::MaxTransferLength(TDmaChannel& /*aChannel*/, TUint /*aSrcFlags*/,
       
   269 									   TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
       
   270 //
       
   271 // Returns the maximum transfer length in bytes for a given transfer.
       
   272 //
       
   273 	{
       
   274 	// TO DO: Determine the proper return value, based on the arguments.
       
   275 
       
   276 	// For instance:
       
   277 	return KMaxTransferLen;
       
   278 	}
       
   279 
       
   280 
       
   281 TUint TTemplateDmac::AddressAlignMask(TDmaChannel& aChannel, TUint /*aSrcFlags*/,
       
   282 									  TUint /*aDstFlags*/, TUint32 /*aPslInfo*/)
       
   283 //
       
   284 // Returns the memory buffer alignment restrictions mask for a given transfer.
       
   285 //
       
   286 	{
       
   287 	// TO DO: Determine the proper return value, based on the arguments.
       
   288 
       
   289 	// For instance:
       
   290 	return KMemAlignMask;
       
   291 	}
       
   292 
       
   293 
       
   294 TInt TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, const TDmaTransferArgs& aTransferArgs)
       
   295 //
       
   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,
       
   299 // transfer width).
       
   300 //
       
   301 	{
       
   302 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   303 
       
   304 	__KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
       
   305 
       
   306 	// Unaligned descriptor? Bug in generic layer!
       
   307 	__DMA_ASSERTD(IsHwDesAligned(pD));
       
   308 
       
   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 	__DMA_ASSERTD(pD->iSrcAddr != KPhysAddrInvalid);
       
   313 	pD->iDestAddr = (dst.iFlags & KDmaPhysAddr) ? dst.iAddr : Epoc::LinearToPhysical(dst.iAddr);
       
   314 	__DMA_ASSERTD(pD->iDestAddr != KPhysAddrInvalid);
       
   315 	pD->iCmd = DmaCmdReg(aTransferArgs.iTransferCount, aTransferArgs.iFlags,
       
   316 					   src.iPslTargetInfo, dst.iPslTargetInfo);
       
   317 	pD->iDescAddr = TDmaDesc::KStopBitMask;
       
   318 
       
   319 	return KErrNone;
       
   320 	}
       
   321 
       
   322 
       
   323 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
       
   324 //
       
   325 // Chains hardware descriptors together by setting the next pointer of the original descriptor
       
   326 // to the physical address of the descriptor to be chained.
       
   327 //
       
   328 	{
       
   329 	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   330 	TDmaDesc* pN = HdrToHwDes(aNextHdr);
       
   331 
       
   332 	__KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
       
   333 
       
   334 	// Unaligned descriptor? Bug in generic layer!
       
   335 	__DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
       
   336 
       
   337 	// TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
       
   338 
       
   339 	pD->iDescAddr = HwDesLinToPhys(pN);
       
   340 	}
       
   341 
       
   342 
       
   343 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
       
   344 								const SDmaDesHdr& aNewHdr)
       
   345 //
       
   346 // Appends a descriptor to the chain while the channel is running.
       
   347 //
       
   348 	{
       
   349 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
       
   350 
       
   351 	TDmaDesc* pL = HdrToHwDes(aLastHdr);
       
   352 	TDmaDesc* pN = HdrToHwDes(aNewHdr);
       
   353 
       
   354 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
       
   355 									i, pL, pN));
       
   356 	// Unaligned descriptor? Bug in generic layer!
       
   357 	__DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
       
   358 
       
   359 	TPhysAddr newPhys = HwDesLinToPhys(pN);
       
   360 
       
   361 	const TInt irq = NKern::DisableAllInterrupts();
       
   362 	StopTransfer(aChannel);
       
   363 
       
   364 	pL->iDescAddr = newPhys;
       
   365 	const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
       
   366 	TDmaDesc* pD = channel.iTmpDes;
       
   367 
       
   368 	// TO DO: Implement the appropriate algorithm for appending a descriptor here.
       
   369 	(void) *pD, (void) i;
       
   370 
       
   371 	NKern::RestoreInterrupts(irq);
       
   372 
       
   373 	__KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
       
   374 	}
       
   375 
       
   376 
       
   377 void TTemplateDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
       
   378 //
       
   379 // Unlink the last item in the h/w descriptor chain from a subsequent chain that it was
       
   380 // possibly linked to.
       
   381 //
       
   382 	{
       
   383  	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::UnlinkHwDes"));
       
   384   	TDmaDesc* pD = HdrToHwDes(aHdr);
       
   385   	pD->iDescAddr = TDmaDesc::KStopBitMask;
       
   386 
       
   387 	// TO DO: Modify pD->iCmd so that an end-of-transfer interrupt will get raised.
       
   388 
       
   389 	}
       
   390 
       
   391 
       
   392 void TTemplateDmac::Isr(TAny* aThis)
       
   393 //
       
   394 // This ISR reads the interrupt identification and calls back into the base class
       
   395 // interrupt service handler with the channel identifier and an indication whether the
       
   396 // transfer completed correctly or with an error.
       
   397 //
       
   398 	{
       
   399 	TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
       
   400 
       
   401 	// TO DO: Implement the behaviour described above, call HandleIsr().
       
   402 
       
   403 	HandleIsr(me.iChannels[5], EDmaCallbackRequestCompletion, ETrue); // Example
       
   404 
       
   405 	}
       
   406 
       
   407 
       
   408 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr)
       
   409 //
       
   410 // Changes return type of base class call.
       
   411 //
       
   412 	{
       
   413 	return static_cast<TDmaDesc*>(TDmac::HdrToHwDes(aHdr));
       
   414 	}
       
   415 
       
   416 
       
   417 //////////////////////////////////////////////////////////////////////////////
       
   418 // Channel Opening/Closing (Channel Allocator)
       
   419 //////////////////////////////////////////////////////////////////////////////
       
   420 
       
   421 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/)
       
   422 //
       
   423 //
       
   424 //
       
   425 	{
       
   426 	__KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
       
   427 
       
   428 	__DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
       
   429 
       
   430 	TDmaChannel* pC = Controller.iChannels + aOpenId;
       
   431 	if (pC->IsOpened())
       
   432 		{
       
   433 		pC = NULL;
       
   434 		}
       
   435 	else
       
   436 		{
       
   437 		pC->iController = &Controller;
       
   438 		pC->iPslId = aOpenId;
       
   439 		}
       
   440 
       
   441 	return pC;
       
   442 	}
       
   443 
       
   444 
       
   445 void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
       
   446 //
       
   447 //
       
   448 //
       
   449 	{
       
   450 	// NOP
       
   451 	}
       
   452 
       
   453 
       
   454 TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
       
   455 //
       
   456 //
       
   457 //
       
   458 	{
       
   459 	return KErrNotSupported;
       
   460 	}
       
   461 
       
   462 
       
   463 //////////////////////////////////////////////////////////////////////////////
       
   464 // DLL Exported Function
       
   465 //////////////////////////////////////////////////////////////////////////////
       
   466 
       
   467 DECLARE_STANDARD_EXTENSION()
       
   468 //
       
   469 // Creates and initializes a new DMA controller object on the kernel heap.
       
   470 //
       
   471 	{
       
   472 	__KTRACE_OPT2(KBOOT, KDMA, Kern::Printf("Starting DMA Extension"));
       
   473 
       
   474 	const TInt r = DmaChannelMgr::Initialise();
       
   475 	if (r != KErrNone)
       
   476 		{
       
   477 		return r;
       
   478 		}
       
   479 	return Controller.Create();
       
   480 	}