Home | History | Annotate | Download | only in dma
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
      4  */
      5 
      6 /*Main C file for multi-channel DMA API. */
      7 
      8 #include <common.h>
      9 
     10 #include <MCD_dma.h>
     11 #include <MCD_tasksInit.h>
     12 #include <MCD_progCheck.h>
     13 
     14 /********************************************************************/
     15 /* This is an API-internal pointer to the DMA's registers */
     16 dmaRegs *MCD_dmaBar;
     17 
     18 /*
     19  * These are the real and model task tables as generated by the
     20  * build process
     21  */
     22 extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
     23 extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
     24 
     25 /*
     26  * However, this (usually) gets relocated to on-chip SRAM, at which
     27  * point we access them as these tables
     28  */
     29 volatile TaskTableEntry *MCD_taskTable;
     30 TaskTableEntry *MCD_modelTaskTable;
     31 
     32 /*
     33  * MCD_chStatus[] is an array of status indicators for remembering
     34  * whether a DMA has ever been attempted on each channel, pausing
     35  * status, etc.
     36  */
     37 static int MCD_chStatus[NCHANNELS] = {
     38 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
     39 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
     40 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
     41 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
     42 };
     43 
     44 /* Prototypes for local functions */
     45 static void MCD_memcpy(int *dest, int *src, u32 size);
     46 static void MCD_resmActions(int channel);
     47 
     48 /*
     49  * Buffer descriptors used for storage of progress info for single Dmas
     50  * Also used as storage for the DMA for CRCs for single DMAs
     51  * Otherwise, the DMA does not parse these buffer descriptors
     52  */
     53 #ifdef MCD_INCLUDE_EU
     54 extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
     55 #else
     56 MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
     57 #endif
     58 MCD_bufDesc *MCD_relocBuffDesc;
     59 
     60 /* Defines for the debug control register's functions */
     61 #define DBG_CTL_COMP1_TASK	(0x00002000)
     62 #define DBG_CTL_ENABLE		(DBG_CTL_AUTO_ARM	| \
     63 				 DBG_CTL_BREAK		| \
     64 				 DBG_CTL_INT_BREAK	| \
     65 				 DBG_CTL_COMP1_TASK)
     66 #define DBG_CTL_DISABLE		(DBG_CTL_AUTO_ARM	| \
     67 				 DBG_CTL_INT_BREAK	| \
     68 				 DBG_CTL_COMP1_TASK)
     69 #define DBG_KILL_ALL_STAT	(0xFFFFFFFF)
     70 
     71 /* Offset to context save area where progress info is stored */
     72 #define CSAVE_OFFSET		10
     73 
     74 /* Defines for Byte Swapping */
     75 #define MCD_BYTE_SWAP_KILLER	0xFFF8888F
     76 #define MCD_NO_BYTE_SWAP_ATALL	0x00040000
     77 
     78 /* Execution Unit Identifiers */
     79 #define MAC			0	/* legacy - not used */
     80 #define LUAC			1	/* legacy - not used */
     81 #define CRC			2	/* legacy - not used */
     82 #define LURC			3	/* Logic Unit with CRC */
     83 
     84 /* Task Identifiers */
     85 #define TASK_CHAINNOEU		0
     86 #define TASK_SINGLENOEU		1
     87 #ifdef MCD_INCLUDE_EU
     88 #define TASK_CHAINEU		2
     89 #define TASK_SINGLEEU		3
     90 #define TASK_FECRX		4
     91 #define TASK_FECTX		5
     92 #else
     93 #define TASK_CHAINEU		0
     94 #define TASK_SINGLEEU		1
     95 #define TASK_FECRX		2
     96 #define TASK_FECTX		3
     97 #endif
     98 
     99 /*
    100  * Structure to remember which variant is on which channel
    101  * TBD- need this?
    102  */
    103 typedef struct MCD_remVariants_struct MCD_remVariant;
    104 struct MCD_remVariants_struct {
    105 	int remDestRsdIncr[NCHANNELS];	/* -1,0,1 */
    106 	int remSrcRsdIncr[NCHANNELS];	/* -1,0,1 */
    107 	s16 remDestIncr[NCHANNELS];	/* DestIncr */
    108 	s16 remSrcIncr[NCHANNELS];	/* srcIncr */
    109 	u32 remXferSize[NCHANNELS];	/* xferSize */
    110 };
    111 
    112 /* Structure to remember the startDma parameters for each channel */
    113 MCD_remVariant MCD_remVariants;
    114 /********************************************************************/
    115 /* Function: MCD_initDma
    116  * Purpose:  Initializes the DMA API by setting up a pointer to the DMA
    117  *           registers, relocating and creating the appropriate task
    118  *           structures, and setting up some global settings
    119  * Arguments:
    120  *  dmaBarAddr    - pointer to the multichannel DMA registers
    121  *  taskTableDest - location to move DMA task code and structs to
    122  *  flags         - operational parameters
    123  * Return Value:
    124  *  MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
    125  *  MCD_OK otherwise
    126  */
    127 extern u32 MCD_funcDescTab0[];
    128 
    129 int MCD_initDma(dmaRegs * dmaBarAddr, void *taskTableDest, u32 flags)
    130 {
    131 	int i;
    132 	TaskTableEntry *entryPtr;
    133 
    134 	/* setup the local pointer to register set */
    135 	MCD_dmaBar = dmaBarAddr;
    136 
    137 	/* do we need to move/create a task table */
    138 	if ((flags & MCD_RELOC_TASKS) != 0) {
    139 		int fixedSize;
    140 		u32 *fixedPtr;
    141 		/*int *tablePtr = taskTableDest;TBD */
    142 		int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
    143 		int taskDescTabsOffset;
    144 		int taskTableSize, varTabsSize, funcDescTabsSize,
    145 		    contextSavesSize;
    146 		int taskDescTabSize;
    147 
    148 		int i;
    149 
    150 		/* check if physical address is aligned on 512 byte boundary */
    151 		if (((u32) taskTableDest & 0x000001ff) != 0)
    152 			return (MCD_TABLE_UNALIGNED);
    153 
    154 		/* set up local pointer to task Table */
    155 		MCD_taskTable = taskTableDest;
    156 
    157 		/*
    158 		 * Create a task table:
    159 		 * - compute aligned base offsets for variable tables and
    160 		 *   function descriptor tables, then
    161 		 * - loop through the task table and setup the pointers
    162 		 * - copy over model task table with the the actual task
    163 		 *   descriptor tables
    164 		 */
    165 
    166 		taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
    167 		/* align variable tables to size */
    168 		varTabsOffset = taskTableSize + (u32) taskTableDest;
    169 		if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
    170 			varTabsOffset =
    171 			    (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
    172 		/* align function descriptor tables */
    173 		varTabsSize = NCHANNELS * VAR_TAB_SIZE;
    174 		funcDescTabsOffset = varTabsOffset + varTabsSize;
    175 
    176 		if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
    177 			funcDescTabsOffset =
    178 			    (funcDescTabsOffset +
    179 			     FUNCDESC_TAB_SIZE) & (~FUNCDESC_TAB_SIZE);
    180 
    181 		funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
    182 		contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
    183 		contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
    184 		fixedSize =
    185 		    taskTableSize + varTabsSize + funcDescTabsSize +
    186 		    contextSavesSize;
    187 
    188 		/* zero the thing out */
    189 		fixedPtr = (u32 *) taskTableDest;
    190 		for (i = 0; i < (fixedSize / 4); i++)
    191 			fixedPtr[i] = 0;
    192 
    193 		entryPtr = (TaskTableEntry *) MCD_taskTable;
    194 		/* set up fixed pointers */
    195 		for (i = 0; i < NCHANNELS; i++) {
    196 			/* update ptr to local value */
    197 			entryPtr[i].varTab = (u32) varTabsOffset;
    198 			entryPtr[i].FDTandFlags =
    199 			    (u32) funcDescTabsOffset | MCD_TT_FLAGS_DEF;
    200 			entryPtr[i].contextSaveSpace = (u32) contextSavesOffset;
    201 			varTabsOffset += VAR_TAB_SIZE;
    202 #ifdef MCD_INCLUDE_EU
    203 			/* if not there is only one, just point to the
    204 			   same one */
    205 			funcDescTabsOffset += FUNCDESC_TAB_SIZE;
    206 #endif
    207 			contextSavesOffset += CONTEXT_SAVE_SIZE;
    208 		}
    209 		/* copy over the function descriptor table */
    210 		for (i = 0; i < FUNCDESC_TAB_NUM; i++) {
    211 			MCD_memcpy((void *)(entryPtr[i].
    212 					    FDTandFlags & ~MCD_TT_FLAGS_MASK),
    213 				   (void *)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
    214 		}
    215 
    216 		/* copy model task table to where the context saves stuff
    217 		   leaves off */
    218 		MCD_modelTaskTable = (TaskTableEntry *) contextSavesOffset;
    219 
    220 		MCD_memcpy((void *)MCD_modelTaskTable,
    221 			   (void *)MCD_modelTaskTableSrc,
    222 			   NUMOFVARIANTS * sizeof(TaskTableEntry));
    223 
    224 		/* point to local version of model task table */
    225 		entryPtr = MCD_modelTaskTable;
    226 		taskDescTabsOffset = (u32) MCD_modelTaskTable +
    227 		    (NUMOFVARIANTS * sizeof(TaskTableEntry));
    228 
    229 		/* copy actual task code and update TDT ptrs in local
    230 		   model task table */
    231 		for (i = 0; i < NUMOFVARIANTS; i++) {
    232 			taskDescTabSize =
    233 			    entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
    234 			MCD_memcpy((void *)taskDescTabsOffset,
    235 				   (void *)entryPtr[i].TDTstart,
    236 				   taskDescTabSize);
    237 			entryPtr[i].TDTstart = (u32) taskDescTabsOffset;
    238 			taskDescTabsOffset += taskDescTabSize;
    239 			entryPtr[i].TDTend = (u32) taskDescTabsOffset - 4;
    240 		}
    241 #ifdef MCD_INCLUDE_EU
    242 		/* Tack single DMA BDs onto end of code so API controls
    243 		   where they are since DMA might write to them */
    244 		MCD_relocBuffDesc =
    245 		    (MCD_bufDesc *) (entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
    246 #else
    247 		/* DMA does not touch them so they can be wherever and we
    248 		   don't need to waste SRAM on them */
    249 		MCD_relocBuffDesc = MCD_singleBufDescs;
    250 #endif
    251 	} else {
    252 		/* point the would-be relocated task tables and the
    253 		   buffer descriptors to the ones the linker generated */
    254 
    255 		if (((u32) MCD_realTaskTableSrc & 0x000001ff) != 0)
    256 			return (MCD_TABLE_UNALIGNED);
    257 
    258 		/* need to add code to make sure that every thing else is
    259 		   aligned properly TBD. this is problematic if we init
    260 		   more than once or after running tasks, need to add
    261 		   variable to see if we have aleady init'd */
    262 		entryPtr = MCD_realTaskTableSrc;
    263 		for (i = 0; i < NCHANNELS; i++) {
    264 			if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
    265 			    ((entryPtr[i].
    266 			      FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
    267 				return (MCD_TABLE_UNALIGNED);
    268 		}
    269 
    270 		MCD_taskTable = MCD_realTaskTableSrc;
    271 		MCD_modelTaskTable = MCD_modelTaskTableSrc;
    272 		MCD_relocBuffDesc = MCD_singleBufDescs;
    273 	}
    274 
    275 	/* Make all channels as totally inactive, and remember them as such: */
    276 
    277 	MCD_dmaBar->taskbar = (u32) MCD_taskTable;
    278 	for (i = 0; i < NCHANNELS; i++) {
    279 		MCD_dmaBar->taskControl[i] = 0x0;
    280 		MCD_chStatus[i] = MCD_NO_DMA;
    281 	}
    282 
    283 	/* Set up pausing mechanism to inactive state: */
    284 	/* no particular values yet for either comparator registers */
    285 	MCD_dmaBar->debugComp1 = 0;
    286 	MCD_dmaBar->debugComp2 = 0;
    287 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
    288 	MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
    289 
    290 	/* enable or disable commbus prefetch, really need an ifdef or
    291 	   something to keep from trying to set this in the 8220 */
    292 	if ((flags & MCD_COMM_PREFETCH_EN) != 0)
    293 		MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
    294 	else
    295 		MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
    296 
    297 	return (MCD_OK);
    298 }
    299 
    300 /*********************** End of MCD_initDma() ***********************/
    301 
    302 /********************************************************************/
    303 /* Function:   MCD_dmaStatus
    304  * Purpose:    Returns the status of the DMA on the requested channel
    305  * Arguments:  channel - channel number
    306  * Returns:    Predefined status indicators
    307  */
    308 int MCD_dmaStatus(int channel)
    309 {
    310 	u16 tcrValue;
    311 
    312 	if ((channel < 0) || (channel >= NCHANNELS))
    313 		return (MCD_CHANNEL_INVALID);
    314 
    315 	tcrValue = MCD_dmaBar->taskControl[channel];
    316 	if ((tcrValue & TASK_CTL_EN) == 0) {	/* nothing running */
    317 		/* if last reported with task enabled */
    318 		if (MCD_chStatus[channel] == MCD_RUNNING
    319 		    || MCD_chStatus[channel] == MCD_IDLE)
    320 			MCD_chStatus[channel] = MCD_DONE;
    321 	} else {		/* something is running */
    322 
    323 		/* There are three possibilities: paused, running or idle. */
    324 		if (MCD_chStatus[channel] == MCD_RUNNING
    325 		    || MCD_chStatus[channel] == MCD_IDLE) {
    326 			MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
    327 			/* This register is selected to know which initiator is
    328 			   actually asserted. */
    329 			if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
    330 				MCD_chStatus[channel] = MCD_RUNNING;
    331 			else
    332 				MCD_chStatus[channel] = MCD_IDLE;
    333 			/* do not change the status if it is already paused. */
    334 		}
    335 	}
    336 	return MCD_chStatus[channel];
    337 }
    338 
    339 /******************** End of MCD_dmaStatus() ************************/
    340 
    341 /********************************************************************/
    342 /* Function:    MCD_startDma
    343  * Ppurpose:    Starts a particular kind of DMA
    344  * Arguments:
    345  * srcAddr	- the channel on which to run the DMA
    346  * srcIncr	- the address to move data from, or buffer-descriptor address
    347  * destAddr	- the amount to increment the source address per transfer
    348  * destIncr	- the address to move data to
    349  * dmaSize	- the amount to increment the destination address per transfer
    350  * xferSize	- the number bytes in of each data movement (1, 2, or 4)
    351  * initiator	- what device initiates the DMA
    352  * priority	- priority of the DMA
    353  * flags	- flags describing the DMA
    354  * funcDesc	- description of byte swapping, bit swapping, and CRC actions
    355  * srcAddrVirt	- virtual buffer descriptor address TBD
    356  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    357  */
    358 
    359 int MCD_startDma(int channel, s8 * srcAddr, s16 srcIncr, s8 * destAddr,
    360 		 s16 destIncr, u32 dmaSize, u32 xferSize, u32 initiator,
    361 		 int priority, u32 flags, u32 funcDesc
    362 #ifdef MCD_NEED_ADDR_TRANS
    363 		 s8 * srcAddrVirt
    364 #endif
    365     )
    366 {
    367 	int srcRsdIncr, destRsdIncr;
    368 	int *cSave;
    369 	short xferSizeIncr;
    370 	int tcrCount = 0;
    371 #ifdef MCD_INCLUDE_EU
    372 	u32 *realFuncArray;
    373 #endif
    374 
    375 	if ((channel < 0) || (channel >= NCHANNELS))
    376 		return (MCD_CHANNEL_INVALID);
    377 
    378 	/* tbd - need to determine the proper response to a bad funcDesc when
    379 	   not including EU functions, for now, assign a benign funcDesc, but
    380 	   maybe should return an error */
    381 #ifndef MCD_INCLUDE_EU
    382 	funcDesc = MCD_FUNC_NOEU1;
    383 #endif
    384 
    385 #ifdef MCD_DEBUG
    386 	printf("startDma:Setting up params\n");
    387 #endif
    388 	/* Set us up for task-wise priority.  We don't technically need to do
    389 	   this on every start, but since the register involved is in the same
    390 	   longword as other registers that users are in control of, setting
    391 	   it more than once is probably preferable.  That since the
    392 	   documentation doesn't seem to be completely consistent about the
    393 	   nature of the PTD control register. */
    394 	MCD_dmaBar->ptdControl |= (u16) 0x8000;
    395 
    396 	/* Not sure what we need to keep here rtm TBD */
    397 #if 1
    398 	/* Calculate additional parameters to the regular DMA calls. */
    399 	srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
    400 	destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
    401 
    402 	xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
    403 
    404 	/* Remember for each channel which variant is running. */
    405 	MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
    406 	MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
    407 	MCD_remVariants.remDestIncr[channel] = destIncr;
    408 	MCD_remVariants.remSrcIncr[channel] = srcIncr;
    409 	MCD_remVariants.remXferSize[channel] = xferSize;
    410 #endif
    411 
    412 	cSave =
    413 	    (int *)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET +
    414 	    CURRBD;
    415 
    416 #ifdef MCD_INCLUDE_EU
    417 	/* may move this to EU specific calls */
    418 	realFuncArray =
    419 	    (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
    420 	/* Modify the LURC's normal and byte-residue-loop functions according
    421 	   to parameter. */
    422 	realFuncArray[(LURC * 16)] = xferSize == 4 ?
    423 	    funcDesc : xferSize == 2 ?
    424 	    funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
    425 	realFuncArray[(LURC * 16 + 1)] =
    426 	    (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
    427 #endif
    428 	/* Write the initiator field in the TCR, and also set the
    429 	   initiator-hold bit. Note that,due to a hardware quirk, this could
    430 	   collide with an MDE access to the initiator-register file, so we
    431 	   have to verify that the write reads back correctly. */
    432 
    433 	MCD_dmaBar->taskControl[channel] =
    434 	    (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
    435 
    436 	while (((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
    437 		((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM))
    438 	       && (tcrCount < 1000)) {
    439 		tcrCount++;
    440 		/*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020; */
    441 		MCD_dmaBar->taskControl[channel] =
    442 		    (initiator << 8) | TASK_CTL_HIPRITSKEN |
    443 		    TASK_CTL_HLDINITNUM;
    444 	}
    445 
    446 	MCD_dmaBar->priority[channel] = (u8) priority & PRIORITY_PRI_MASK;
    447 	/* should be albe to handle this stuff with only one write to ts reg
    448 	   - tbd */
    449 	if (channel < 8 && channel >= 0) {
    450 		MCD_dmaBar->taskSize0 &= ~(0xf << (7 - channel) * 4);
    451 		MCD_dmaBar->taskSize0 |=
    452 		    (xferSize & 3) << (((7 - channel) * 4) + 2);
    453 		MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel) * 4);
    454 	} else {
    455 		MCD_dmaBar->taskSize1 &= ~(0xf << (15 - channel) * 4);
    456 		MCD_dmaBar->taskSize1 |=
    457 		    (xferSize & 3) << (((15 - channel) * 4) + 2);
    458 		MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel) * 4);
    459 	}
    460 
    461 	/* setup task table flags/options which mostly control the line
    462 	   buffers */
    463 	MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
    464 	MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
    465 
    466 	if (flags & MCD_FECTX_DMA) {
    467 		/* TDTStart and TDTEnd */
    468 		MCD_taskTable[channel].TDTstart =
    469 		    MCD_modelTaskTable[TASK_FECTX].TDTstart;
    470 		MCD_taskTable[channel].TDTend =
    471 		    MCD_modelTaskTable[TASK_FECTX].TDTend;
    472 		MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
    473 				     (char *)destAddr, MCD_taskTable,
    474 				     channel);
    475 	} else if (flags & MCD_FECRX_DMA) {
    476 		/* TDTStart and TDTEnd */
    477 		MCD_taskTable[channel].TDTstart =
    478 		    MCD_modelTaskTable[TASK_FECRX].TDTstart;
    479 		MCD_taskTable[channel].TDTend =
    480 		    MCD_modelTaskTable[TASK_FECRX].TDTend;
    481 		MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
    482 				    (char *)destAddr, MCD_taskTable,
    483 				    channel);
    484 	} else if (flags & MCD_SINGLE_DMA) {
    485 		/* this buffer descriptor is used for storing off initial
    486 		   parameters for later progress query calculation and for the
    487 		   DMA to write the resulting checksum. The DMA does not use
    488 		   this to determine how to operate, that info is passed with
    489 		   the init routine */
    490 		MCD_relocBuffDesc[channel].srcAddr = srcAddr;
    491 		MCD_relocBuffDesc[channel].destAddr = destAddr;
    492 
    493 		/* definitely not its final value */
    494 		MCD_relocBuffDesc[channel].lastDestAddr = destAddr;
    495 
    496 		MCD_relocBuffDesc[channel].dmaSize = dmaSize;
    497 		MCD_relocBuffDesc[channel].flags = 0;	/* not used */
    498 		MCD_relocBuffDesc[channel].csumResult = 0;	/* not used */
    499 		MCD_relocBuffDesc[channel].next = 0;	/* not used */
    500 
    501 		/* Initialize the progress-querying stuff to show no
    502 		   progress: */
    503 		((volatile int *)MCD_taskTable[channel].
    504 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
    505 		((volatile int *)MCD_taskTable[channel].
    506 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
    507 		((volatile int *)MCD_taskTable[channel].
    508 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
    509 		((volatile int *)MCD_taskTable[channel].
    510 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
    511 (u32) & (MCD_relocBuffDesc[channel]);
    512 		/* tbd - need to keep the user from trying to call the EU
    513 		   routine when MCD_INCLUDE_EU is not defined */
    514 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
    515 			/* TDTStart and TDTEnd */
    516 			MCD_taskTable[channel].TDTstart =
    517 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
    518 			MCD_taskTable[channel].TDTend =
    519 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
    520 			MCD_startDmaSingleNoEu((char *)srcAddr, srcIncr,
    521 					       (char *)destAddr, destIncr,
    522 					       (int)dmaSize, xferSizeIncr,
    523 					       flags, (int *)
    524 					       &(MCD_relocBuffDesc[channel]),
    525 					       cSave, MCD_taskTable, channel);
    526 		} else {
    527 			/* TDTStart and TDTEnd */
    528 			MCD_taskTable[channel].TDTstart =
    529 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
    530 			MCD_taskTable[channel].TDTend =
    531 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
    532 			MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
    533 					     (char *)destAddr, destIncr,
    534 					     (int)dmaSize, xferSizeIncr,
    535 					     flags, (int *)
    536 					     &(MCD_relocBuffDesc[channel]),
    537 					     cSave, MCD_taskTable, channel);
    538 		}
    539 	} else {		/* chained DMAS */
    540 		/* Initialize the progress-querying stuff to show no
    541 		   progress: */
    542 #if 1
    543 		/* (!defined(MCD_NEED_ADDR_TRANS)) */
    544 		((volatile int *)MCD_taskTable[channel].
    545 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
    546 		    = (int)((MCD_bufDesc *) srcAddr)->srcAddr;
    547 		((volatile int *)MCD_taskTable[channel].
    548 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
    549 		    = (int)((MCD_bufDesc *) srcAddr)->destAddr;
    550 #else
    551 		/* if using address translation, need the virtual addr of the
    552 		   first buffdesc */
    553 		((volatile int *)MCD_taskTable[channel].
    554 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
    555 		    = (int)((MCD_bufDesc *) srcAddrVirt)->srcAddr;
    556 		((volatile int *)MCD_taskTable[channel].
    557 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
    558 		    = (int)((MCD_bufDesc *) srcAddrVirt)->destAddr;
    559 #endif
    560 		((volatile int *)MCD_taskTable[channel].
    561 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
    562 		((volatile int *)MCD_taskTable[channel].
    563 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
    564 
    565 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
    566 			/*TDTStart and TDTEnd */
    567 			MCD_taskTable[channel].TDTstart =
    568 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
    569 			MCD_taskTable[channel].TDTend =
    570 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
    571 			MCD_startDmaChainNoEu((int *)srcAddr, srcIncr,
    572 					      destIncr, xferSize,
    573 					      xferSizeIncr, cSave,
    574 					      MCD_taskTable, channel);
    575 		} else {
    576 			/*TDTStart and TDTEnd */
    577 			MCD_taskTable[channel].TDTstart =
    578 			    MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
    579 			MCD_taskTable[channel].TDTend =
    580 			    MCD_modelTaskTable[TASK_CHAINEU].TDTend;
    581 			MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr,
    582 					    xferSize, xferSizeIncr, cSave,
    583 					    MCD_taskTable, channel);
    584 		}
    585 	}
    586 	MCD_chStatus[channel] = MCD_IDLE;
    587 	return (MCD_OK);
    588 }
    589 
    590 /************************ End of MCD_startDma() *********************/
    591 
    592 /********************************************************************/
    593 /* Function:    MCD_XferProgrQuery
    594  * Purpose:     Returns progress of DMA on requested channel
    595  * Arguments:   channel - channel to retrieve progress for
    596  *              progRep - pointer to user supplied MCD_XferProg struct
    597  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    598  *
    599  * Notes:
    600  *  MCD_XferProgrQuery() upon completing or after aborting a DMA, or
    601  *  while the DMA is in progress, this function returns the first
    602  *  DMA-destination address not (or not yet) used in the DMA. When
    603  *  encountering a non-ready buffer descriptor, the information for
    604  *  the last completed descriptor is returned.
    605  *
    606  *  MCD_XferProgQuery() has to avoid the possibility of getting
    607  *  partially-updated information in the event that we should happen
    608  *  to query DMA progress just as the DMA is updating it. It does that
    609  *  by taking advantage of the fact context is not saved frequently for
    610  *  the most part. We therefore read it at least twice until we get the
    611  *  same information twice in a row.
    612  *
    613  *  Because a small, but not insignificant, amount of time is required
    614  *  to write out the progress-query information, especially upon
    615  *  completion of the DMA, it would be wise to guarantee some time lag
    616  *  between successive readings of the progress-query information.
    617  */
    618 
    619 /* How many iterations of the loop below to execute to stabilize values */
    620 #define STABTIME 0
    621 
    622 int MCD_XferProgrQuery(int channel, MCD_XferProg * progRep)
    623 {
    624 	MCD_XferProg prevRep;
    625 	int again;		/* true if we are to try again to ge
    626 				   consistent results */
    627 	int i;			/* used as a time-waste counter */
    628 	int destDiffBytes;	/* Total no of bytes that we think actually
    629 				   got xfered. */
    630 	int numIterations;	/* number of iterations */
    631 	int bytesNotXfered;	/* bytes that did not get xfered. */
    632 	s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
    633 	int subModVal, addModVal;	/* Mode values to added and subtracted
    634 					   from the final destAddr */
    635 
    636 	if ((channel < 0) || (channel >= NCHANNELS))
    637 		return (MCD_CHANNEL_INVALID);
    638 
    639 	/* Read a trial value for the progress-reporting values */
    640 	prevRep.lastSrcAddr =
    641 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
    642 		    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
    643 	prevRep.lastDestAddr =
    644 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
    645 		    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
    646 	prevRep.dmaSize =
    647 	    ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT +
    648 								      CSAVE_OFFSET];
    649 	prevRep.currBufDesc =
    650 	    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
    651 			     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
    652 	/* Repeatedly reread those values until they match previous values: */
    653 	do {
    654 		/* Waste a little bit of time to ensure stability: */
    655 		for (i = 0; i < STABTIME; i++) {
    656 			/* make sure this loop does something so that it
    657 			   doesn't get optimized out */
    658 			i += i >> 2;
    659 		}
    660 		/* Check them again: */
    661 		progRep->lastSrcAddr =
    662 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
    663 			    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
    664 		progRep->lastDestAddr =
    665 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
    666 			    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
    667 		progRep->dmaSize =
    668 		    ((volatile int *)MCD_taskTable[channel].
    669 		     contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
    670 		progRep->currBufDesc =
    671 		    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
    672 				     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
    673 		/* See if they match: */
    674 		if (prevRep.lastSrcAddr != progRep->lastSrcAddr
    675 		    || prevRep.lastDestAddr != progRep->lastDestAddr
    676 		    || prevRep.dmaSize != progRep->dmaSize
    677 		    || prevRep.currBufDesc != progRep->currBufDesc) {
    678 			/* If they don't match, remember previous values and
    679 			   try again: */
    680 			prevRep.lastSrcAddr = progRep->lastSrcAddr;
    681 			prevRep.lastDestAddr = progRep->lastDestAddr;
    682 			prevRep.dmaSize = progRep->dmaSize;
    683 			prevRep.currBufDesc = progRep->currBufDesc;
    684 			again = MCD_TRUE;
    685 		} else
    686 			again = MCD_FALSE;
    687 	} while (again == MCD_TRUE);
    688 
    689 	/* Update the dCount, srcAddr and destAddr */
    690 	/* To calculate dmaCount, we consider destination address. C
    691 	   overs M1,P1,Z for destination */
    692 	switch (MCD_remVariants.remDestRsdIncr[channel]) {
    693 	case MINUS1:
    694 		subModVal =
    695 		    ((int)progRep->
    696 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
    697 				      1);
    698 		addModVal =
    699 		    ((int)progRep->currBufDesc->
    700 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
    701 		LWAlignedInitDestAddr =
    702 		    (progRep->currBufDesc->destAddr) - addModVal;
    703 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
    704 		destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
    705 		bytesNotXfered =
    706 		    (destDiffBytes / MCD_remVariants.remDestIncr[channel]) *
    707 		    (MCD_remVariants.remDestIncr[channel]
    708 		     + MCD_remVariants.remXferSize[channel]);
    709 		progRep->dmaSize =
    710 		    destDiffBytes - bytesNotXfered + addModVal - subModVal;
    711 		break;
    712 	case ZERO:
    713 		progRep->lastDestAddr = progRep->currBufDesc->destAddr;
    714 		break;
    715 	case PLUS1:
    716 		/* This value has to be subtracted from the final
    717 		   calculated dCount. */
    718 		subModVal =
    719 		    ((int)progRep->currBufDesc->
    720 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
    721 		/* These bytes are already in lastDestAddr. */
    722 		addModVal =
    723 		    ((int)progRep->
    724 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
    725 				      1);
    726 		LWAlignedInitDestAddr =
    727 		    (progRep->currBufDesc->destAddr) - subModVal;
    728 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
    729 		destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
    730 		numIterations =
    731 		    (LWAlignedCurrDestAddr -
    732 		     LWAlignedInitDestAddr) /
    733 		    MCD_remVariants.remDestIncr[channel];
    734 		bytesNotXfered =
    735 		    numIterations * (MCD_remVariants.remDestIncr[channel]
    736 				     - MCD_remVariants.remXferSize[channel]);
    737 		progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
    738 		break;
    739 	default:
    740 		break;
    741 	}
    742 
    743 	/* This covers M1,P1,Z for source */
    744 	switch (MCD_remVariants.remSrcRsdIncr[channel]) {
    745 	case MINUS1:
    746 		progRep->lastSrcAddr =
    747 		    progRep->currBufDesc->srcAddr +
    748 		    (MCD_remVariants.remSrcIncr[channel] *
    749 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
    750 		break;
    751 	case ZERO:
    752 		progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
    753 		break;
    754 	case PLUS1:
    755 		progRep->lastSrcAddr =
    756 		    progRep->currBufDesc->srcAddr +
    757 		    (MCD_remVariants.remSrcIncr[channel] *
    758 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
    759 		break;
    760 	default:
    761 		break;
    762 	}
    763 
    764 	return (MCD_OK);
    765 }
    766 
    767 /******************* End of MCD_XferProgrQuery() ********************/
    768 
    769 /********************************************************************/
    770 /* MCD_resmActions() does the majority of the actions of a DMA resume.
    771  * It is called from MCD_killDma() and MCD_resumeDma().  It has to be
    772  * a separate function because the kill function has to negate the task
    773  * enable before resuming it, but the resume function has to do nothing
    774  * if there is no DMA on that channel (i.e., if the enable bit is 0).
    775  */
    776 static void MCD_resmActions(int channel)
    777 {
    778 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
    779 	MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
    780 	/* This register is selected to know which initiator is
    781 	   actually asserted. */
    782 	MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
    783 
    784 	if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
    785 		MCD_chStatus[channel] = MCD_RUNNING;
    786 	else
    787 		MCD_chStatus[channel] = MCD_IDLE;
    788 }
    789 
    790 /********************* End of MCD_resmActions() *********************/
    791 
    792 /********************************************************************/
    793 /* Function:    MCD_killDma
    794  * Purpose:     Halt the DMA on the requested channel, without any
    795  *              intention of resuming the DMA.
    796  * Arguments:   channel - requested channel
    797  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    798  *
    799  * Notes:
    800  *  A DMA may be killed from any state, including paused state, and it
    801  *  always goes to the MCD_HALTED state even if it is killed while in
    802  *  the MCD_NO_DMA or MCD_IDLE states.
    803  */
    804 int MCD_killDma(int channel)
    805 {
    806 	/* MCD_XferProg progRep; */
    807 
    808 	if ((channel < 0) || (channel >= NCHANNELS))
    809 		return (MCD_CHANNEL_INVALID);
    810 
    811 	MCD_dmaBar->taskControl[channel] = 0x0;
    812 	MCD_resumeDma(channel);
    813 	/*
    814 	 * This must be after the write to the TCR so that the task doesn't
    815 	 * start up again momentarily, and before the status assignment so
    816 	 * as to override whatever MCD_resumeDma() may do to the channel
    817 	 * status.
    818 	 */
    819 	MCD_chStatus[channel] = MCD_HALTED;
    820 
    821 	/*
    822 	 * Update the current buffer descriptor's lastDestAddr field
    823 	 *
    824 	 * MCD_XferProgrQuery (channel, &progRep);
    825 	 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
    826 	 */
    827 	return (MCD_OK);
    828 }
    829 
    830 /************************ End of MCD_killDma() **********************/
    831 
    832 /********************************************************************/
    833 /* Function:    MCD_continDma
    834  * Purpose:     Continue a DMA which as stopped due to encountering an
    835  *              unready buffer descriptor.
    836  * Arguments:   channel - channel to continue the DMA on
    837  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    838  *
    839  * Notes:
    840  *  This routine does not check to see if there is a task which can
    841  *  be continued. Also this routine should not be used with single DMAs.
    842  */
    843 int MCD_continDma(int channel)
    844 {
    845 	if ((channel < 0) || (channel >= NCHANNELS))
    846 		return (MCD_CHANNEL_INVALID);
    847 
    848 	MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
    849 	MCD_chStatus[channel] = MCD_RUNNING;
    850 
    851 	return (MCD_OK);
    852 }
    853 
    854 /********************** End of MCD_continDma() **********************/
    855 
    856 /*********************************************************************
    857  * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
    858  * to freeze a task and resume it.  We freeze a task by breakpointing
    859  * on the stated task.  That is, not any specific place in the task,
    860  * but any time that task executes.  In particular, when that task
    861  * executes, we want to freeze that task and only that task.
    862  *
    863  * The bits of the debug control register influence interrupts vs.
    864  * breakpoints as follows:
    865  * - Bits 14 and 0 enable or disable debug functions.  If enabled, you
    866  *   will get the interrupt but you may or may not get a breakpoint.
    867  * - Bits 2 and 1 decide whether you also get a breakpoint in addition
    868  *   to an interrupt.
    869  *
    870  * The debug unit can do these actions in response to either internally
    871  * detected breakpoint conditions from the comparators, or in response
    872  * to the external breakpoint pin, or both.
    873  * - Bits 14 and 1 perform the above-described functions for
    874  *   internally-generated conditions, i.e., the debug comparators.
    875  * - Bits 0 and 2 perform the above-described functions for external
    876  *   conditions, i.e., the breakpoint external pin.
    877  *
    878  * Note that, although you "always" get the interrupt when you turn
    879  * the debug functions, the interrupt can nevertheless, if desired, be
    880  * masked by the corresponding bit in the PTD's IMR. Note also that
    881  * this means that bits 14 and 0 must enable debug functions before
    882  * bits 1 and 2, respectively, have any effect.
    883  *
    884  * NOTE: It's extremely important to not pause more than one DMA channel
    885  *  at a time.
    886  ********************************************************************/
    887 
    888 /********************************************************************/
    889 /* Function:    MCD_pauseDma
    890  * Purpose:     Pauses the DMA on a given channel (if any DMA is running
    891  *              on that channel).
    892  * Arguments:   channel
    893  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    894  */
    895 int MCD_pauseDma(int channel)
    896 {
    897 	/* MCD_XferProg progRep; */
    898 
    899 	if ((channel < 0) || (channel >= NCHANNELS))
    900 		return (MCD_CHANNEL_INVALID);
    901 
    902 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) {
    903 		MCD_dmaBar->debugComp1 = channel;
    904 		MCD_dmaBar->debugControl =
    905 		    DBG_CTL_ENABLE | (1 << (channel + 16));
    906 		MCD_chStatus[channel] = MCD_PAUSED;
    907 
    908 		/*
    909 		 * Update the current buffer descriptor's lastDestAddr field
    910 		 *
    911 		 * MCD_XferProgrQuery (channel, &progRep);
    912 		 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
    913 		 */
    914 	}
    915 	return (MCD_OK);
    916 }
    917 
    918 /************************* End of MCD_pauseDma() ********************/
    919 
    920 /********************************************************************/
    921 /* Function:    MCD_resumeDma
    922  * Purpose:     Resumes the DMA on a given channel (if any DMA is
    923  *              running on that channel).
    924  * Arguments:   channel - channel on which to resume DMA
    925  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
    926  */
    927 int MCD_resumeDma(int channel)
    928 {
    929 	if ((channel < 0) || (channel >= NCHANNELS))
    930 		return (MCD_CHANNEL_INVALID);
    931 
    932 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
    933 		MCD_resmActions(channel);
    934 
    935 	return (MCD_OK);
    936 }
    937 
    938 /************************ End of MCD_resumeDma() ********************/
    939 
    940 /********************************************************************/
    941 /* Function:    MCD_csumQuery
    942  * Purpose:     Provide the checksum after performing a non-chained DMA
    943  * Arguments:   channel - channel to report on
    944  *              csum - pointer to where to write the checksum/CRC
    945  * Returns:     MCD_ERROR if the channel is invalid, else MCD_OK
    946  *
    947  * Notes:
    948  *
    949  */
    950 int MCD_csumQuery(int channel, u32 * csum)
    951 {
    952 #ifdef MCD_INCLUDE_EU
    953 	if ((channel < 0) || (channel >= NCHANNELS))
    954 		return (MCD_CHANNEL_INVALID);
    955 
    956 	*csum = MCD_relocBuffDesc[channel].csumResult;
    957 	return (MCD_OK);
    958 #else
    959 	return (MCD_ERROR);
    960 #endif
    961 }
    962 
    963 /*********************** End of MCD_resumeDma() *********************/
    964 
    965 /********************************************************************/
    966 /* Function:    MCD_getCodeSize
    967  * Purpose:     Provide the size requirements of the microcoded tasks
    968  * Returns:     Size in bytes
    969  */
    970 int MCD_getCodeSize(void)
    971 {
    972 #ifdef MCD_INCLUDE_EU
    973 	return (0x2b5c);
    974 #else
    975 	return (0x173c);
    976 #endif
    977 }
    978 
    979 /********************** End of MCD_getCodeSize() ********************/
    980 
    981 /********************************************************************/
    982 /* Function:    MCD_getVersion
    983  * Purpose:     Provide the version string and number
    984  * Arguments:   longVersion - user supplied pointer to a pointer to a char
    985  *                    which points to the version string
    986  * Returns:     Version number and version string (by reference)
    987  */
    988 char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
    989 #define MCD_REV_MAJOR   0x00
    990 #define MCD_REV_MINOR   0x03
    991 
    992 int MCD_getVersion(char **longVersion)
    993 {
    994 	*longVersion = MCD_versionString;
    995 	return ((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
    996 }
    997 
    998 /********************** End of MCD_getVersion() *********************/
    999 
   1000 /********************************************************************/
   1001 /* Private version of memcpy()
   1002  * Note that everything this is used for is longword-aligned.
   1003  */
   1004 static void MCD_memcpy(int *dest, int *src, u32 size)
   1005 {
   1006 	u32 i;
   1007 
   1008 	for (i = 0; i < size; i += sizeof(int), dest++, src++)
   1009 		*dest = *src;
   1010 }
   1011