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