os/kernelhwsrv/bsptemplate/asspandvariant/template_assp/dmapsl.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // bsptemplate/asspvariant/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 
    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 	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;
   316 
   317 	return KErrNone;
   318 	}
   319 
   320 
   321 void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
   322 //
   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.
   325 //
   326 	{
   327 	TDmaDesc* pD = HdrToHwDes(aHdr);
   328 	TDmaDesc* pN = HdrToHwDes(aNextHdr);
   329 
   330 	__KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
   331 
   332 	// Unaligned descriptor? Bug in generic layer!
   333 	__DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
   334 
   335 	// TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer.
   336 
   337 	pD->iDescAddr = HwDesLinToPhys(pN);
   338 	}
   339 
   340 
   341 void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
   342 								const SDmaDesHdr& aNewHdr)
   343 //
   344 // Appends a descriptor to the chain while the channel is running.
   345 //
   346 	{
   347 	const TUint8 i = static_cast<TUint8>(aChannel.PslId());
   348 
   349 	TDmaDesc* pL = HdrToHwDes(aLastHdr);
   350 	TDmaDesc* pN = HdrToHwDes(aNewHdr);
   351 
   352 	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
   353 									i, pL, pN));
   354 	// Unaligned descriptor? Bug in generic layer!
   355 	__DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
   356 
   357 	TPhysAddr newPhys = HwDesLinToPhys(pN);
   358 
   359 	const TInt irq = NKern::DisableAllInterrupts();
   360 	StopTransfer(aChannel);
   361 
   362 	pL->iDescAddr = newPhys;
   363 	const TTemplateSgChannel& channel = static_cast<const TTemplateSgChannel&>(aChannel);
   364 	TDmaDesc* pD = channel.iTmpDes;
   365 
   366 	// TO DO: Implement the appropriate algorithm for appending a descriptor here.
   367 	(void) *pD, (void) i;
   368 
   369 	NKern::RestoreInterrupts(irq);
   370 
   371 	__KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes"));
   372 	}
   373 
   374 
   375 void TTemplateDmac::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
   376 //
   377 // Unlink the last item in the h/w descriptor chain from a subsequent chain that it was
   378 // possibly linked to.
   379 //
   380 	{
   381  	__KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::UnlinkHwDes"));
   382   	TDmaDesc* pD = HdrToHwDes(aHdr);
   383   	pD->iDescAddr = TDmaDesc::KStopBitMask;
   384 
   385 	// TO DO: Modify pD->iCmd so that an end-of-transfer interrupt will get raised.
   386 
   387 	}
   388 
   389 
   390 void TTemplateDmac::Isr(TAny* aThis)
   391 //
   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.
   395 //
   396 	{
   397 	TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis);
   398 
   399 	// TO DO: Implement the behaviour described above, call HandleIsr().
   400 
   401 	HandleIsr(me.iChannels[5], EDmaCallbackRequestCompletion, ETrue); // Example
   402 
   403 	}
   404 
   405 
   406 inline TDmaDesc* TTemplateDmac::HdrToHwDes(const SDmaDesHdr& aHdr)
   407 //
   408 // Changes return type of base class call.
   409 //
   410 	{
   411 	return static_cast<TDmaDesc*>(TDmac::HdrToHwDes(aHdr));
   412 	}
   413 
   414 
   415 //////////////////////////////////////////////////////////////////////////////
   416 // Channel Opening/Closing (Channel Allocator)
   417 //////////////////////////////////////////////////////////////////////////////
   418 
   419 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId, TBool /*aDynChannel*/, TUint /*aPriority*/)
   420 //
   421 //
   422 //
   423 	{
   424 	__KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId));
   425 
   426 	__DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount));
   427 
   428 	TDmaChannel* pC = Controller.iChannels + aOpenId;
   429 	if (pC->IsOpened())
   430 		{
   431 		pC = NULL;
   432 		}
   433 	else
   434 		{
   435 		pC->iController = &Controller;
   436 		pC->iPslId = aOpenId;
   437 		}
   438 
   439 	return pC;
   440 	}
   441 
   442 
   443 void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
   444 //
   445 //
   446 //
   447 	{
   448 	// NOP
   449 	}
   450 
   451 
   452 TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
   453 //
   454 //
   455 //
   456 	{
   457 	return KErrNotSupported;
   458 	}
   459 
   460 
   461 //////////////////////////////////////////////////////////////////////////////
   462 // DLL Exported Function
   463 //////////////////////////////////////////////////////////////////////////////
   464 
   465 DECLARE_STANDARD_EXTENSION()
   466 //
   467 // Creates and initializes a new DMA controller object on the kernel heap.
   468 //
   469 	{
   470 	__KTRACE_OPT2(KBOOT, KDMA, Kern::Printf("Starting DMA Extension"));
   471 
   472 	const TInt r = DmaChannelMgr::Initialise();
   473 	if (r != KErrNone)
   474 		{
   475 		return r;
   476 		}
   477 	return Controller.Create();
   478 	}