mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	Change %08lX to %08X in board.c. Remove unused variable 'oscillator' in mcf5227x/cpu_init.c and 'scm2' in mcf532x/cpu_init.c. Provide argument type cast in drivers/dma/MCD_dmaApi.c. Signed-off-by: TsiChung Liew <tsicliew@gmail.com>
		
			
				
	
	
		
			1028 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1028 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
 | |
|  *
 | |
|  * See file CREDITS for list of people who contributed to this
 | |
|  * project.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License as
 | |
|  * published by the Free Software Foundation; either version 2 of
 | |
|  * the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software
 | |
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 | |
|  * MA 02111-1307 USA
 | |
|  */
 | |
| 
 | |
| /*Main C file for multi-channel DMA API. */
 | |
| 
 | |
| #include <common.h>
 | |
| 
 | |
| #include <MCD_dma.h>
 | |
| #include <MCD_tasksInit.h>
 | |
| #include <MCD_progCheck.h>
 | |
| 
 | |
| /********************************************************************/
 | |
| /* This is an API-internal pointer to the DMA's registers */
 | |
| dmaRegs *MCD_dmaBar;
 | |
| 
 | |
| /*
 | |
|  * These are the real and model task tables as generated by the
 | |
|  * build process
 | |
|  */
 | |
| extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS];
 | |
| extern TaskTableEntry MCD_modelTaskTableSrc[NUMOFVARIANTS];
 | |
| 
 | |
| /*
 | |
|  * However, this (usually) gets relocated to on-chip SRAM, at which
 | |
|  * point we access them as these tables
 | |
|  */
 | |
| volatile TaskTableEntry *MCD_taskTable;
 | |
| TaskTableEntry *MCD_modelTaskTable;
 | |
| 
 | |
| /*
 | |
|  * MCD_chStatus[] is an array of status indicators for remembering
 | |
|  * whether a DMA has ever been attempted on each channel, pausing
 | |
|  * status, etc.
 | |
|  */
 | |
| static int MCD_chStatus[NCHANNELS] = {
 | |
| 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
 | |
| 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
 | |
| 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA,
 | |
| 	MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA, MCD_NO_DMA
 | |
| };
 | |
| 
 | |
| /* Prototypes for local functions */
 | |
| static void MCD_memcpy(int *dest, int *src, u32 size);
 | |
| static void MCD_resmActions(int channel);
 | |
| 
 | |
| /*
 | |
|  * Buffer descriptors used for storage of progress info for single Dmas
 | |
|  * Also used as storage for the DMA for CRCs for single DMAs
 | |
|  * Otherwise, the DMA does not parse these buffer descriptors
 | |
|  */
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
 | |
| #else
 | |
| MCD_bufDesc MCD_singleBufDescs[NCHANNELS];
 | |
| #endif
 | |
| MCD_bufDesc *MCD_relocBuffDesc;
 | |
| 
 | |
| /* Defines for the debug control register's functions */
 | |
| #define DBG_CTL_COMP1_TASK	(0x00002000)
 | |
| #define DBG_CTL_ENABLE		(DBG_CTL_AUTO_ARM	| \
 | |
| 				 DBG_CTL_BREAK		| \
 | |
| 				 DBG_CTL_INT_BREAK	| \
 | |
| 				 DBG_CTL_COMP1_TASK)
 | |
| #define DBG_CTL_DISABLE		(DBG_CTL_AUTO_ARM	| \
 | |
| 				 DBG_CTL_INT_BREAK	| \
 | |
| 				 DBG_CTL_COMP1_TASK)
 | |
| #define DBG_KILL_ALL_STAT	(0xFFFFFFFF)
 | |
| 
 | |
| /* Offset to context save area where progress info is stored */
 | |
| #define CSAVE_OFFSET		10
 | |
| 
 | |
| /* Defines for Byte Swapping */
 | |
| #define MCD_BYTE_SWAP_KILLER	0xFFF8888F
 | |
| #define MCD_NO_BYTE_SWAP_ATALL	0x00040000
 | |
| 
 | |
| /* Execution Unit Identifiers */
 | |
| #define MAC			0	/* legacy - not used */
 | |
| #define LUAC			1	/* legacy - not used */
 | |
| #define CRC			2	/* legacy - not used */
 | |
| #define LURC			3	/* Logic Unit with CRC */
 | |
| 
 | |
| /* Task Identifiers */
 | |
| #define TASK_CHAINNOEU		0
 | |
| #define TASK_SINGLENOEU		1
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| #define TASK_CHAINEU		2
 | |
| #define TASK_SINGLEEU		3
 | |
| #define TASK_FECRX		4
 | |
| #define TASK_FECTX		5
 | |
| #else
 | |
| #define TASK_CHAINEU		0
 | |
| #define TASK_SINGLEEU		1
 | |
| #define TASK_FECRX		2
 | |
| #define TASK_FECTX		3
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Structure to remember which variant is on which channel
 | |
|  * TBD- need this?
 | |
|  */
 | |
| typedef struct MCD_remVariants_struct MCD_remVariant;
 | |
| struct MCD_remVariants_struct {
 | |
| 	int remDestRsdIncr[NCHANNELS];	/* -1,0,1 */
 | |
| 	int remSrcRsdIncr[NCHANNELS];	/* -1,0,1 */
 | |
| 	s16 remDestIncr[NCHANNELS];	/* DestIncr */
 | |
| 	s16 remSrcIncr[NCHANNELS];	/* srcIncr */
 | |
| 	u32 remXferSize[NCHANNELS];	/* xferSize */
 | |
| };
 | |
| 
 | |
| /* Structure to remember the startDma parameters for each channel */
 | |
| MCD_remVariant MCD_remVariants;
 | |
| /********************************************************************/
 | |
| /* Function: MCD_initDma
 | |
|  * Purpose:  Initializes the DMA API by setting up a pointer to the DMA
 | |
|  *           registers, relocating and creating the appropriate task
 | |
|  *           structures, and setting up some global settings
 | |
|  * Arguments:
 | |
|  *  dmaBarAddr    - pointer to the multichannel DMA registers
 | |
|  *  taskTableDest - location to move DMA task code and structs to
 | |
|  *  flags         - operational parameters
 | |
|  * Return Value:
 | |
|  *  MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned
 | |
|  *  MCD_OK otherwise
 | |
|  */
 | |
| extern u32 MCD_funcDescTab0[];
 | |
| 
 | |
| int MCD_initDma(dmaRegs * dmaBarAddr, void *taskTableDest, u32 flags)
 | |
| {
 | |
| 	int i;
 | |
| 	TaskTableEntry *entryPtr;
 | |
| 
 | |
| 	/* setup the local pointer to register set */
 | |
| 	MCD_dmaBar = dmaBarAddr;
 | |
| 
 | |
| 	/* do we need to move/create a task table */
 | |
| 	if ((flags & MCD_RELOC_TASKS) != 0) {
 | |
| 		int fixedSize;
 | |
| 		u32 *fixedPtr;
 | |
| 		/*int *tablePtr = taskTableDest;TBD */
 | |
| 		int varTabsOffset, funcDescTabsOffset, contextSavesOffset;
 | |
| 		int taskDescTabsOffset;
 | |
| 		int taskTableSize, varTabsSize, funcDescTabsSize,
 | |
| 		    contextSavesSize;
 | |
| 		int taskDescTabSize;
 | |
| 
 | |
| 		int i;
 | |
| 
 | |
| 		/* check if physical address is aligned on 512 byte boundary */
 | |
| 		if (((u32) taskTableDest & 0x000001ff) != 0)
 | |
| 			return (MCD_TABLE_UNALIGNED);
 | |
| 
 | |
| 		/* set up local pointer to task Table */
 | |
| 		MCD_taskTable = taskTableDest;
 | |
| 
 | |
| 		/*
 | |
| 		 * Create a task table:
 | |
| 		 * - compute aligned base offsets for variable tables and
 | |
| 		 *   function descriptor tables, then
 | |
| 		 * - loop through the task table and setup the pointers
 | |
| 		 * - copy over model task table with the the actual task
 | |
| 		 *   descriptor tables
 | |
| 		 */
 | |
| 
 | |
| 		taskTableSize = NCHANNELS * sizeof(TaskTableEntry);
 | |
| 		/* align variable tables to size */
 | |
| 		varTabsOffset = taskTableSize + (u32) taskTableDest;
 | |
| 		if ((varTabsOffset & (VAR_TAB_SIZE - 1)) != 0)
 | |
| 			varTabsOffset =
 | |
| 			    (varTabsOffset + VAR_TAB_SIZE) & (~VAR_TAB_SIZE);
 | |
| 		/* align function descriptor tables */
 | |
| 		varTabsSize = NCHANNELS * VAR_TAB_SIZE;
 | |
| 		funcDescTabsOffset = varTabsOffset + varTabsSize;
 | |
| 
 | |
| 		if ((funcDescTabsOffset & (FUNCDESC_TAB_SIZE - 1)) != 0)
 | |
| 			funcDescTabsOffset =
 | |
| 			    (funcDescTabsOffset +
 | |
| 			     FUNCDESC_TAB_SIZE) & (~FUNCDESC_TAB_SIZE);
 | |
| 
 | |
| 		funcDescTabsSize = FUNCDESC_TAB_NUM * FUNCDESC_TAB_SIZE;
 | |
| 		contextSavesOffset = funcDescTabsOffset + funcDescTabsSize;
 | |
| 		contextSavesSize = (NCHANNELS * CONTEXT_SAVE_SIZE);
 | |
| 		fixedSize =
 | |
| 		    taskTableSize + varTabsSize + funcDescTabsSize +
 | |
| 		    contextSavesSize;
 | |
| 
 | |
| 		/* zero the thing out */
 | |
| 		fixedPtr = (u32 *) taskTableDest;
 | |
| 		for (i = 0; i < (fixedSize / 4); i++)
 | |
| 			fixedPtr[i] = 0;
 | |
| 
 | |
| 		entryPtr = (TaskTableEntry *) MCD_taskTable;
 | |
| 		/* set up fixed pointers */
 | |
| 		for (i = 0; i < NCHANNELS; i++) {
 | |
| 			/* update ptr to local value */
 | |
| 			entryPtr[i].varTab = (u32) varTabsOffset;
 | |
| 			entryPtr[i].FDTandFlags =
 | |
| 			    (u32) funcDescTabsOffset | MCD_TT_FLAGS_DEF;
 | |
| 			entryPtr[i].contextSaveSpace = (u32) contextSavesOffset;
 | |
| 			varTabsOffset += VAR_TAB_SIZE;
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 			/* if not there is only one, just point to the
 | |
| 			   same one */
 | |
| 			funcDescTabsOffset += FUNCDESC_TAB_SIZE;
 | |
| #endif
 | |
| 			contextSavesOffset += CONTEXT_SAVE_SIZE;
 | |
| 		}
 | |
| 		/* copy over the function descriptor table */
 | |
| 		for (i = 0; i < FUNCDESC_TAB_NUM; i++) {
 | |
| 			MCD_memcpy((void *)(entryPtr[i].
 | |
| 					    FDTandFlags & ~MCD_TT_FLAGS_MASK),
 | |
| 				   (void *)MCD_funcDescTab0, FUNCDESC_TAB_SIZE);
 | |
| 		}
 | |
| 
 | |
| 		/* copy model task table to where the context saves stuff
 | |
| 		   leaves off */
 | |
| 		MCD_modelTaskTable = (TaskTableEntry *) contextSavesOffset;
 | |
| 
 | |
| 		MCD_memcpy((void *)MCD_modelTaskTable,
 | |
| 			   (void *)MCD_modelTaskTableSrc,
 | |
| 			   NUMOFVARIANTS * sizeof(TaskTableEntry));
 | |
| 
 | |
| 		/* point to local version of model task table */
 | |
| 		entryPtr = MCD_modelTaskTable;
 | |
| 		taskDescTabsOffset = (u32) MCD_modelTaskTable +
 | |
| 		    (NUMOFVARIANTS * sizeof(TaskTableEntry));
 | |
| 
 | |
| 		/* copy actual task code and update TDT ptrs in local
 | |
| 		   model task table */
 | |
| 		for (i = 0; i < NUMOFVARIANTS; i++) {
 | |
| 			taskDescTabSize =
 | |
| 			    entryPtr[i].TDTend - entryPtr[i].TDTstart + 4;
 | |
| 			MCD_memcpy((void *)taskDescTabsOffset,
 | |
| 				   (void *)entryPtr[i].TDTstart,
 | |
| 				   taskDescTabSize);
 | |
| 			entryPtr[i].TDTstart = (u32) taskDescTabsOffset;
 | |
| 			taskDescTabsOffset += taskDescTabSize;
 | |
| 			entryPtr[i].TDTend = (u32) taskDescTabsOffset - 4;
 | |
| 		}
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 		/* Tack single DMA BDs onto end of code so API controls
 | |
| 		   where they are since DMA might write to them */
 | |
| 		MCD_relocBuffDesc =
 | |
| 		    (MCD_bufDesc *) (entryPtr[NUMOFVARIANTS - 1].TDTend + 4);
 | |
| #else
 | |
| 		/* DMA does not touch them so they can be wherever and we
 | |
| 		   don't need to waste SRAM on them */
 | |
| 		MCD_relocBuffDesc = MCD_singleBufDescs;
 | |
| #endif
 | |
| 	} else {
 | |
| 		/* point the would-be relocated task tables and the
 | |
| 		   buffer descriptors to the ones the linker generated */
 | |
| 
 | |
| 		if (((u32) MCD_realTaskTableSrc & 0x000001ff) != 0)
 | |
| 			return (MCD_TABLE_UNALIGNED);
 | |
| 
 | |
| 		/* need to add code to make sure that every thing else is
 | |
| 		   aligned properly TBD. this is problematic if we init
 | |
| 		   more than once or after running tasks, need to add
 | |
| 		   variable to see if we have aleady init'd */
 | |
| 		entryPtr = MCD_realTaskTableSrc;
 | |
| 		for (i = 0; i < NCHANNELS; i++) {
 | |
| 			if (((entryPtr[i].varTab & (VAR_TAB_SIZE - 1)) != 0) ||
 | |
| 			    ((entryPtr[i].
 | |
| 			      FDTandFlags & (FUNCDESC_TAB_SIZE - 1)) != 0))
 | |
| 				return (MCD_TABLE_UNALIGNED);
 | |
| 		}
 | |
| 
 | |
| 		MCD_taskTable = MCD_realTaskTableSrc;
 | |
| 		MCD_modelTaskTable = MCD_modelTaskTableSrc;
 | |
| 		MCD_relocBuffDesc = MCD_singleBufDescs;
 | |
| 	}
 | |
| 
 | |
| 	/* Make all channels as totally inactive, and remember them as such: */
 | |
| 
 | |
| 	MCD_dmaBar->taskbar = (u32) MCD_taskTable;
 | |
| 	for (i = 0; i < NCHANNELS; i++) {
 | |
| 		MCD_dmaBar->taskControl[i] = 0x0;
 | |
| 		MCD_chStatus[i] = MCD_NO_DMA;
 | |
| 	}
 | |
| 
 | |
| 	/* Set up pausing mechanism to inactive state: */
 | |
| 	/* no particular values yet for either comparator registers */
 | |
| 	MCD_dmaBar->debugComp1 = 0;
 | |
| 	MCD_dmaBar->debugComp2 = 0;
 | |
| 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
 | |
| 	MCD_dmaBar->debugStatus = DBG_KILL_ALL_STAT;
 | |
| 
 | |
| 	/* enable or disable commbus prefetch, really need an ifdef or
 | |
| 	   something to keep from trying to set this in the 8220 */
 | |
| 	if ((flags & MCD_COMM_PREFETCH_EN) != 0)
 | |
| 		MCD_dmaBar->ptdControl &= ~PTD_CTL_COMM_PREFETCH;
 | |
| 	else
 | |
| 		MCD_dmaBar->ptdControl |= PTD_CTL_COMM_PREFETCH;
 | |
| 
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /*********************** End of MCD_initDma() ***********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:   MCD_dmaStatus
 | |
|  * Purpose:    Returns the status of the DMA on the requested channel
 | |
|  * Arguments:  channel - channel number
 | |
|  * Returns:    Predefined status indicators
 | |
|  */
 | |
| int MCD_dmaStatus(int channel)
 | |
| {
 | |
| 	u16 tcrValue;
 | |
| 
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	tcrValue = MCD_dmaBar->taskControl[channel];
 | |
| 	if ((tcrValue & TASK_CTL_EN) == 0) {	/* nothing running */
 | |
| 		/* if last reported with task enabled */
 | |
| 		if (MCD_chStatus[channel] == MCD_RUNNING
 | |
| 		    || MCD_chStatus[channel] == MCD_IDLE)
 | |
| 			MCD_chStatus[channel] = MCD_DONE;
 | |
| 	} else {		/* something is running */
 | |
| 
 | |
| 		/* There are three possibilities: paused, running or idle. */
 | |
| 		if (MCD_chStatus[channel] == MCD_RUNNING
 | |
| 		    || MCD_chStatus[channel] == MCD_IDLE) {
 | |
| 			MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
 | |
| 			/* This register is selected to know which initiator is
 | |
| 			   actually asserted. */
 | |
| 			if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
 | |
| 				MCD_chStatus[channel] = MCD_RUNNING;
 | |
| 			else
 | |
| 				MCD_chStatus[channel] = MCD_IDLE;
 | |
| 			/* do not change the status if it is already paused. */
 | |
| 		}
 | |
| 	}
 | |
| 	return MCD_chStatus[channel];
 | |
| }
 | |
| 
 | |
| /******************** End of MCD_dmaStatus() ************************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_startDma
 | |
|  * Ppurpose:    Starts a particular kind of DMA
 | |
|  * Arguments:
 | |
|  * srcAddr	- the channel on which to run the DMA
 | |
|  * srcIncr	- the address to move data from, or buffer-descriptor address
 | |
|  * destAddr	- the amount to increment the source address per transfer
 | |
|  * destIncr	- the address to move data to
 | |
|  * dmaSize	- the amount to increment the destination address per transfer
 | |
|  * xferSize	- the number bytes in of each data movement (1, 2, or 4)
 | |
|  * initiator	- what device initiates the DMA
 | |
|  * priority	- priority of the DMA
 | |
|  * flags	- flags describing the DMA
 | |
|  * funcDesc	- description of byte swapping, bit swapping, and CRC actions
 | |
|  * srcAddrVirt	- virtual buffer descriptor address TBD
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  */
 | |
| 
 | |
| int MCD_startDma(int channel, s8 * srcAddr, s16 srcIncr, s8 * destAddr,
 | |
| 		 s16 destIncr, u32 dmaSize, u32 xferSize, u32 initiator,
 | |
| 		 int priority, u32 flags, u32 funcDesc
 | |
| #ifdef MCD_NEED_ADDR_TRANS
 | |
| 		 s8 * srcAddrVirt
 | |
| #endif
 | |
|     )
 | |
| {
 | |
| 	int srcRsdIncr, destRsdIncr;
 | |
| 	int *cSave;
 | |
| 	short xferSizeIncr;
 | |
| 	int tcrCount = 0;
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 	u32 *realFuncArray;
 | |
| #endif
 | |
| 
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	/* tbd - need to determine the proper response to a bad funcDesc when
 | |
| 	   not including EU functions, for now, assign a benign funcDesc, but
 | |
| 	   maybe should return an error */
 | |
| #ifndef MCD_INCLUDE_EU
 | |
| 	funcDesc = MCD_FUNC_NOEU1;
 | |
| #endif
 | |
| 
 | |
| #ifdef MCD_DEBUG
 | |
| 	printf("startDma:Setting up params\n");
 | |
| #endif
 | |
| 	/* Set us up for task-wise priority.  We don't technically need to do
 | |
| 	   this on every start, but since the register involved is in the same
 | |
| 	   longword as other registers that users are in control of, setting
 | |
| 	   it more than once is probably preferable.  That since the
 | |
| 	   documentation doesn't seem to be completely consistent about the
 | |
| 	   nature of the PTD control register. */
 | |
| 	MCD_dmaBar->ptdControl |= (u16) 0x8000;
 | |
| 
 | |
| 	/* Not sure what we need to keep here rtm TBD */
 | |
| #if 1
 | |
| 	/* Calculate additional parameters to the regular DMA calls. */
 | |
| 	srcRsdIncr = srcIncr < 0 ? -1 : (srcIncr > 0 ? 1 : 0);
 | |
| 	destRsdIncr = destIncr < 0 ? -1 : (destIncr > 0 ? 1 : 0);
 | |
| 
 | |
| 	xferSizeIncr = (xferSize & 0xffff) | 0x20000000;
 | |
| 
 | |
| 	/* Remember for each channel which variant is running. */
 | |
| 	MCD_remVariants.remSrcRsdIncr[channel] = srcRsdIncr;
 | |
| 	MCD_remVariants.remDestRsdIncr[channel] = destRsdIncr;
 | |
| 	MCD_remVariants.remDestIncr[channel] = destIncr;
 | |
| 	MCD_remVariants.remSrcIncr[channel] = srcIncr;
 | |
| 	MCD_remVariants.remXferSize[channel] = xferSize;
 | |
| #endif
 | |
| 
 | |
| 	cSave =
 | |
| 	    (int *)(MCD_taskTable[channel].contextSaveSpace) + CSAVE_OFFSET +
 | |
| 	    CURRBD;
 | |
| 
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 	/* may move this to EU specific calls */
 | |
| 	realFuncArray =
 | |
| 	    (u32 *) (MCD_taskTable[channel].FDTandFlags & 0xffffff00);
 | |
| 	/* Modify the LURC's normal and byte-residue-loop functions according
 | |
| 	   to parameter. */
 | |
| 	realFuncArray[(LURC * 16)] = xferSize == 4 ?
 | |
| 	    funcDesc : xferSize == 2 ?
 | |
| 	    funcDesc & 0xfffff00f : funcDesc & 0xffff000f;
 | |
| 	realFuncArray[(LURC * 16 + 1)] =
 | |
| 	    (funcDesc & MCD_BYTE_SWAP_KILLER) | MCD_NO_BYTE_SWAP_ATALL;
 | |
| #endif
 | |
| 	/* Write the initiator field in the TCR, and also set the
 | |
| 	   initiator-hold bit. Note that,due to a hardware quirk, this could
 | |
| 	   collide with an MDE access to the initiator-register file, so we
 | |
| 	   have to verify that the write reads back correctly. */
 | |
| 
 | |
| 	MCD_dmaBar->taskControl[channel] =
 | |
| 	    (initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM;
 | |
| 
 | |
| 	while (((MCD_dmaBar->taskControl[channel] & 0x1fff) !=
 | |
| 		((initiator << 8) | TASK_CTL_HIPRITSKEN | TASK_CTL_HLDINITNUM))
 | |
| 	       && (tcrCount < 1000)) {
 | |
| 		tcrCount++;
 | |
| 		/*MCD_dmaBar->ptd_tcr[channel] = (initiator << 8) | 0x0020; */
 | |
| 		MCD_dmaBar->taskControl[channel] =
 | |
| 		    (initiator << 8) | TASK_CTL_HIPRITSKEN |
 | |
| 		    TASK_CTL_HLDINITNUM;
 | |
| 	}
 | |
| 
 | |
| 	MCD_dmaBar->priority[channel] = (u8) priority & PRIORITY_PRI_MASK;
 | |
| 	/* should be albe to handle this stuff with only one write to ts reg
 | |
| 	   - tbd */
 | |
| 	if (channel < 8 && channel >= 0) {
 | |
| 		MCD_dmaBar->taskSize0 &= ~(0xf << (7 - channel) * 4);
 | |
| 		MCD_dmaBar->taskSize0 |=
 | |
| 		    (xferSize & 3) << (((7 - channel) * 4) + 2);
 | |
| 		MCD_dmaBar->taskSize0 |= (xferSize & 3) << ((7 - channel) * 4);
 | |
| 	} else {
 | |
| 		MCD_dmaBar->taskSize1 &= ~(0xf << (15 - channel) * 4);
 | |
| 		MCD_dmaBar->taskSize1 |=
 | |
| 		    (xferSize & 3) << (((15 - channel) * 4) + 2);
 | |
| 		MCD_dmaBar->taskSize1 |= (xferSize & 3) << ((15 - channel) * 4);
 | |
| 	}
 | |
| 
 | |
| 	/* setup task table flags/options which mostly control the line
 | |
| 	   buffers */
 | |
| 	MCD_taskTable[channel].FDTandFlags &= ~MCD_TT_FLAGS_MASK;
 | |
| 	MCD_taskTable[channel].FDTandFlags |= (MCD_TT_FLAGS_MASK & flags);
 | |
| 
 | |
| 	if (flags & MCD_FECTX_DMA) {
 | |
| 		/* TDTStart and TDTEnd */
 | |
| 		MCD_taskTable[channel].TDTstart =
 | |
| 		    MCD_modelTaskTable[TASK_FECTX].TDTstart;
 | |
| 		MCD_taskTable[channel].TDTend =
 | |
| 		    MCD_modelTaskTable[TASK_FECTX].TDTend;
 | |
| 		MCD_startDmaENetXmit((char *)srcAddr, (char *)srcAddr,
 | |
| 				     (char *)destAddr, MCD_taskTable,
 | |
| 				     channel);
 | |
| 	} else if (flags & MCD_FECRX_DMA) {
 | |
| 		/* TDTStart and TDTEnd */
 | |
| 		MCD_taskTable[channel].TDTstart =
 | |
| 		    MCD_modelTaskTable[TASK_FECRX].TDTstart;
 | |
| 		MCD_taskTable[channel].TDTend =
 | |
| 		    MCD_modelTaskTable[TASK_FECRX].TDTend;
 | |
| 		MCD_startDmaENetRcv((char *)srcAddr, (char *)srcAddr,
 | |
| 				    (char *)destAddr, MCD_taskTable,
 | |
| 				    channel);
 | |
| 	} else if (flags & MCD_SINGLE_DMA) {
 | |
| 		/* this buffer descriptor is used for storing off initial
 | |
| 		   parameters for later progress query calculation and for the
 | |
| 		   DMA to write the resulting checksum. The DMA does not use
 | |
| 		   this to determine how to operate, that info is passed with
 | |
| 		   the init routine */
 | |
| 		MCD_relocBuffDesc[channel].srcAddr = srcAddr;
 | |
| 		MCD_relocBuffDesc[channel].destAddr = destAddr;
 | |
| 
 | |
| 		/* definitely not its final value */
 | |
| 		MCD_relocBuffDesc[channel].lastDestAddr = destAddr;
 | |
| 
 | |
| 		MCD_relocBuffDesc[channel].dmaSize = dmaSize;
 | |
| 		MCD_relocBuffDesc[channel].flags = 0;	/* not used */
 | |
| 		MCD_relocBuffDesc[channel].csumResult = 0;	/* not used */
 | |
| 		MCD_relocBuffDesc[channel].next = 0;	/* not used */
 | |
| 
 | |
| 		/* Initialize the progress-querying stuff to show no
 | |
| 		   progress: */
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET] = (int)srcAddr;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET] = (int)destAddr;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] =
 | |
| (u32) & (MCD_relocBuffDesc[channel]);
 | |
| 		/* tbd - need to keep the user from trying to call the EU
 | |
| 		   routine when MCD_INCLUDE_EU is not defined */
 | |
| 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
 | |
| 			/* TDTStart and TDTEnd */
 | |
| 			MCD_taskTable[channel].TDTstart =
 | |
| 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTstart;
 | |
| 			MCD_taskTable[channel].TDTend =
 | |
| 			    MCD_modelTaskTable[TASK_SINGLENOEU].TDTend;
 | |
| 			MCD_startDmaSingleNoEu((char *)srcAddr, srcIncr,
 | |
| 					       (char *)destAddr, destIncr,
 | |
| 					       (int)dmaSize, xferSizeIncr,
 | |
| 					       flags, (int *)
 | |
| 					       &(MCD_relocBuffDesc[channel]),
 | |
| 					       cSave, MCD_taskTable, channel);
 | |
| 		} else {
 | |
| 			/* TDTStart and TDTEnd */
 | |
| 			MCD_taskTable[channel].TDTstart =
 | |
| 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTstart;
 | |
| 			MCD_taskTable[channel].TDTend =
 | |
| 			    MCD_modelTaskTable[TASK_SINGLEEU].TDTend;
 | |
| 			MCD_startDmaSingleEu((char *)srcAddr, srcIncr,
 | |
| 					     (char *)destAddr, destIncr,
 | |
| 					     (int)dmaSize, xferSizeIncr,
 | |
| 					     flags, (int *)
 | |
| 					     &(MCD_relocBuffDesc[channel]),
 | |
| 					     cSave, MCD_taskTable, channel);
 | |
| 		}
 | |
| 	} else {		/* chained DMAS */
 | |
| 		/* Initialize the progress-querying stuff to show no
 | |
| 		   progress: */
 | |
| #if 1
 | |
| 		/* (!defined(MCD_NEED_ADDR_TRANS)) */
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
 | |
| 		    = (int)((MCD_bufDesc *) srcAddr)->srcAddr;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
 | |
| 		    = (int)((MCD_bufDesc *) srcAddr)->destAddr;
 | |
| #else
 | |
| 		/* if using address translation, need the virtual addr of the
 | |
| 		   first buffdesc */
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[SRCPTR + CSAVE_OFFSET]
 | |
| 		    = (int)((MCD_bufDesc *) srcAddrVirt)->srcAddr;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[DESTPTR + CSAVE_OFFSET]
 | |
| 		    = (int)((MCD_bufDesc *) srcAddrVirt)->destAddr;
 | |
| #endif
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[DCOUNT + CSAVE_OFFSET] = 0;
 | |
| 		((volatile int *)MCD_taskTable[channel].
 | |
| 		 contextSaveSpace)[CURRBD + CSAVE_OFFSET] = (u32) srcAddr;
 | |
| 
 | |
| 		if (funcDesc == MCD_FUNC_NOEU1 || funcDesc == MCD_FUNC_NOEU2) {
 | |
| 			/*TDTStart and TDTEnd */
 | |
| 			MCD_taskTable[channel].TDTstart =
 | |
| 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTstart;
 | |
| 			MCD_taskTable[channel].TDTend =
 | |
| 			    MCD_modelTaskTable[TASK_CHAINNOEU].TDTend;
 | |
| 			MCD_startDmaChainNoEu((int *)srcAddr, srcIncr,
 | |
| 					      destIncr, xferSize,
 | |
| 					      xferSizeIncr, cSave,
 | |
| 					      MCD_taskTable, channel);
 | |
| 		} else {
 | |
| 			/*TDTStart and TDTEnd */
 | |
| 			MCD_taskTable[channel].TDTstart =
 | |
| 			    MCD_modelTaskTable[TASK_CHAINEU].TDTstart;
 | |
| 			MCD_taskTable[channel].TDTend =
 | |
| 			    MCD_modelTaskTable[TASK_CHAINEU].TDTend;
 | |
| 			MCD_startDmaChainEu((int *)srcAddr, srcIncr, destIncr,
 | |
| 					    xferSize, xferSizeIncr, cSave,
 | |
| 					    MCD_taskTable, channel);
 | |
| 		}
 | |
| 	}
 | |
| 	MCD_chStatus[channel] = MCD_IDLE;
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /************************ End of MCD_startDma() *********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_XferProgrQuery
 | |
|  * Purpose:     Returns progress of DMA on requested channel
 | |
|  * Arguments:   channel - channel to retrieve progress for
 | |
|  *              progRep - pointer to user supplied MCD_XferProg struct
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  *
 | |
|  * Notes:
 | |
|  *  MCD_XferProgrQuery() upon completing or after aborting a DMA, or
 | |
|  *  while the DMA is in progress, this function returns the first
 | |
|  *  DMA-destination address not (or not yet) used in the DMA. When
 | |
|  *  encountering a non-ready buffer descriptor, the information for
 | |
|  *  the last completed descriptor is returned.
 | |
|  *
 | |
|  *  MCD_XferProgQuery() has to avoid the possibility of getting
 | |
|  *  partially-updated information in the event that we should happen
 | |
|  *  to query DMA progress just as the DMA is updating it. It does that
 | |
|  *  by taking advantage of the fact context is not saved frequently for
 | |
|  *  the most part. We therefore read it at least twice until we get the
 | |
|  *  same information twice in a row.
 | |
|  *
 | |
|  *  Because a small, but not insignificant, amount of time is required
 | |
|  *  to write out the progress-query information, especially upon
 | |
|  *  completion of the DMA, it would be wise to guarantee some time lag
 | |
|  *  between successive readings of the progress-query information.
 | |
|  */
 | |
| 
 | |
| /* How many iterations of the loop below to execute to stabilize values */
 | |
| #define STABTIME 0
 | |
| 
 | |
| int MCD_XferProgrQuery(int channel, MCD_XferProg * progRep)
 | |
| {
 | |
| 	MCD_XferProg prevRep;
 | |
| 	int again;		/* true if we are to try again to ge
 | |
| 				   consistent results */
 | |
| 	int i;			/* used as a time-waste counter */
 | |
| 	int destDiffBytes;	/* Total no of bytes that we think actually
 | |
| 				   got xfered. */
 | |
| 	int numIterations;	/* number of iterations */
 | |
| 	int bytesNotXfered;	/* bytes that did not get xfered. */
 | |
| 	s8 *LWAlignedInitDestAddr, *LWAlignedCurrDestAddr;
 | |
| 	int subModVal, addModVal;	/* Mode values to added and subtracted
 | |
| 					   from the final destAddr */
 | |
| 
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	/* Read a trial value for the progress-reporting values */
 | |
| 	prevRep.lastSrcAddr =
 | |
| 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
 | |
| 		    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
 | |
| 	prevRep.lastDestAddr =
 | |
| 	    (s8 *) ((volatile int *)MCD_taskTable[channel].
 | |
| 		    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
 | |
| 	prevRep.dmaSize =
 | |
| 	    ((volatile int *)MCD_taskTable[channel].contextSaveSpace)[DCOUNT +
 | |
| 								      CSAVE_OFFSET];
 | |
| 	prevRep.currBufDesc =
 | |
| 	    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
 | |
| 			     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
 | |
| 	/* Repeatedly reread those values until they match previous values: */
 | |
| 	do {
 | |
| 		/* Waste a little bit of time to ensure stability: */
 | |
| 		for (i = 0; i < STABTIME; i++) {
 | |
| 			/* make sure this loop does something so that it
 | |
| 			   doesn't get optimized out */
 | |
| 			i += i >> 2;
 | |
| 		}
 | |
| 		/* Check them again: */
 | |
| 		progRep->lastSrcAddr =
 | |
| 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
 | |
| 			    contextSaveSpace)[SRCPTR + CSAVE_OFFSET];
 | |
| 		progRep->lastDestAddr =
 | |
| 		    (s8 *) ((volatile int *)MCD_taskTable[channel].
 | |
| 			    contextSaveSpace)[DESTPTR + CSAVE_OFFSET];
 | |
| 		progRep->dmaSize =
 | |
| 		    ((volatile int *)MCD_taskTable[channel].
 | |
| 		     contextSaveSpace)[DCOUNT + CSAVE_OFFSET];
 | |
| 		progRep->currBufDesc =
 | |
| 		    (MCD_bufDesc *) ((volatile int *)MCD_taskTable[channel].
 | |
| 				     contextSaveSpace)[CURRBD + CSAVE_OFFSET];
 | |
| 		/* See if they match: */
 | |
| 		if (prevRep.lastSrcAddr != progRep->lastSrcAddr
 | |
| 		    || prevRep.lastDestAddr != progRep->lastDestAddr
 | |
| 		    || prevRep.dmaSize != progRep->dmaSize
 | |
| 		    || prevRep.currBufDesc != progRep->currBufDesc) {
 | |
| 			/* If they don't match, remember previous values and
 | |
| 			   try again: */
 | |
| 			prevRep.lastSrcAddr = progRep->lastSrcAddr;
 | |
| 			prevRep.lastDestAddr = progRep->lastDestAddr;
 | |
| 			prevRep.dmaSize = progRep->dmaSize;
 | |
| 			prevRep.currBufDesc = progRep->currBufDesc;
 | |
| 			again = MCD_TRUE;
 | |
| 		} else
 | |
| 			again = MCD_FALSE;
 | |
| 	} while (again == MCD_TRUE);
 | |
| 
 | |
| 	/* Update the dCount, srcAddr and destAddr */
 | |
| 	/* To calculate dmaCount, we consider destination address. C
 | |
| 	   overs M1,P1,Z for destination */
 | |
| 	switch (MCD_remVariants.remDestRsdIncr[channel]) {
 | |
| 	case MINUS1:
 | |
| 		subModVal =
 | |
| 		    ((int)progRep->
 | |
| 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
 | |
| 				      1);
 | |
| 		addModVal =
 | |
| 		    ((int)progRep->currBufDesc->
 | |
| 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
 | |
| 		LWAlignedInitDestAddr =
 | |
| 		    (progRep->currBufDesc->destAddr) - addModVal;
 | |
| 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - subModVal;
 | |
| 		destDiffBytes = LWAlignedInitDestAddr - LWAlignedCurrDestAddr;
 | |
| 		bytesNotXfered =
 | |
| 		    (destDiffBytes / MCD_remVariants.remDestIncr[channel]) *
 | |
| 		    (MCD_remVariants.remDestIncr[channel]
 | |
| 		     + MCD_remVariants.remXferSize[channel]);
 | |
| 		progRep->dmaSize =
 | |
| 		    destDiffBytes - bytesNotXfered + addModVal - subModVal;
 | |
| 		break;
 | |
| 	case ZERO:
 | |
| 		progRep->lastDestAddr = progRep->currBufDesc->destAddr;
 | |
| 		break;
 | |
| 	case PLUS1:
 | |
| 		/* This value has to be subtracted from the final
 | |
| 		   calculated dCount. */
 | |
| 		subModVal =
 | |
| 		    ((int)progRep->currBufDesc->
 | |
| 		     destAddr) & ((MCD_remVariants.remXferSize[channel]) - 1);
 | |
| 		/* These bytes are already in lastDestAddr. */
 | |
| 		addModVal =
 | |
| 		    ((int)progRep->
 | |
| 		     lastDestAddr) & ((MCD_remVariants.remXferSize[channel]) -
 | |
| 				      1);
 | |
| 		LWAlignedInitDestAddr =
 | |
| 		    (progRep->currBufDesc->destAddr) - subModVal;
 | |
| 		LWAlignedCurrDestAddr = (progRep->lastDestAddr) - addModVal;
 | |
| 		destDiffBytes = (progRep->lastDestAddr - LWAlignedInitDestAddr);
 | |
| 		numIterations =
 | |
| 		    (LWAlignedCurrDestAddr -
 | |
| 		     LWAlignedInitDestAddr) /
 | |
| 		    MCD_remVariants.remDestIncr[channel];
 | |
| 		bytesNotXfered =
 | |
| 		    numIterations * (MCD_remVariants.remDestIncr[channel]
 | |
| 				     - MCD_remVariants.remXferSize[channel]);
 | |
| 		progRep->dmaSize = destDiffBytes - bytesNotXfered - subModVal;
 | |
| 		break;
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	/* This covers M1,P1,Z for source */
 | |
| 	switch (MCD_remVariants.remSrcRsdIncr[channel]) {
 | |
| 	case MINUS1:
 | |
| 		progRep->lastSrcAddr =
 | |
| 		    progRep->currBufDesc->srcAddr +
 | |
| 		    (MCD_remVariants.remSrcIncr[channel] *
 | |
| 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
 | |
| 		break;
 | |
| 	case ZERO:
 | |
| 		progRep->lastSrcAddr = progRep->currBufDesc->srcAddr;
 | |
| 		break;
 | |
| 	case PLUS1:
 | |
| 		progRep->lastSrcAddr =
 | |
| 		    progRep->currBufDesc->srcAddr +
 | |
| 		    (MCD_remVariants.remSrcIncr[channel] *
 | |
| 		     (progRep->dmaSize / MCD_remVariants.remXferSize[channel]));
 | |
| 		break;
 | |
| 	default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /******************* End of MCD_XferProgrQuery() ********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* MCD_resmActions() does the majority of the actions of a DMA resume.
 | |
|  * It is called from MCD_killDma() and MCD_resumeDma().  It has to be
 | |
|  * a separate function because the kill function has to negate the task
 | |
|  * enable before resuming it, but the resume function has to do nothing
 | |
|  * if there is no DMA on that channel (i.e., if the enable bit is 0).
 | |
|  */
 | |
| static void MCD_resmActions(int channel)
 | |
| {
 | |
| 	MCD_dmaBar->debugControl = DBG_CTL_DISABLE;
 | |
| 	MCD_dmaBar->debugStatus = MCD_dmaBar->debugStatus;
 | |
| 	/* This register is selected to know which initiator is
 | |
| 	   actually asserted. */
 | |
| 	MCD_dmaBar->ptdDebug = PTD_DBG_TSK_VLD_INIT;
 | |
| 
 | |
| 	if ((MCD_dmaBar->ptdDebug >> channel) & 0x1)
 | |
| 		MCD_chStatus[channel] = MCD_RUNNING;
 | |
| 	else
 | |
| 		MCD_chStatus[channel] = MCD_IDLE;
 | |
| }
 | |
| 
 | |
| /********************* End of MCD_resmActions() *********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_killDma
 | |
|  * Purpose:     Halt the DMA on the requested channel, without any
 | |
|  *              intention of resuming the DMA.
 | |
|  * Arguments:   channel - requested channel
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  *
 | |
|  * Notes:
 | |
|  *  A DMA may be killed from any state, including paused state, and it
 | |
|  *  always goes to the MCD_HALTED state even if it is killed while in
 | |
|  *  the MCD_NO_DMA or MCD_IDLE states.
 | |
|  */
 | |
| int MCD_killDma(int channel)
 | |
| {
 | |
| 	/* MCD_XferProg progRep; */
 | |
| 
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	MCD_dmaBar->taskControl[channel] = 0x0;
 | |
| 	MCD_resumeDma(channel);
 | |
| 	/*
 | |
| 	 * This must be after the write to the TCR so that the task doesn't
 | |
| 	 * start up again momentarily, and before the status assignment so
 | |
| 	 * as to override whatever MCD_resumeDma() may do to the channel
 | |
| 	 * status.
 | |
| 	 */
 | |
| 	MCD_chStatus[channel] = MCD_HALTED;
 | |
| 
 | |
| 	/*
 | |
| 	 * Update the current buffer descriptor's lastDestAddr field
 | |
| 	 *
 | |
| 	 * MCD_XferProgrQuery (channel, &progRep);
 | |
| 	 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
 | |
| 	 */
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /************************ End of MCD_killDma() **********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_continDma
 | |
|  * Purpose:     Continue a DMA which as stopped due to encountering an
 | |
|  *              unready buffer descriptor.
 | |
|  * Arguments:   channel - channel to continue the DMA on
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  *
 | |
|  * Notes:
 | |
|  *  This routine does not check to see if there is a task which can
 | |
|  *  be continued. Also this routine should not be used with single DMAs.
 | |
|  */
 | |
| int MCD_continDma(int channel)
 | |
| {
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	MCD_dmaBar->taskControl[channel] |= TASK_CTL_EN;
 | |
| 	MCD_chStatus[channel] = MCD_RUNNING;
 | |
| 
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /********************** End of MCD_continDma() **********************/
 | |
| 
 | |
| /*********************************************************************
 | |
|  * MCD_pauseDma() and MCD_resumeDma() below use the DMA's debug unit
 | |
|  * to freeze a task and resume it.  We freeze a task by breakpointing
 | |
|  * on the stated task.  That is, not any specific place in the task,
 | |
|  * but any time that task executes.  In particular, when that task
 | |
|  * executes, we want to freeze that task and only that task.
 | |
|  *
 | |
|  * The bits of the debug control register influence interrupts vs.
 | |
|  * breakpoints as follows:
 | |
|  * - Bits 14 and 0 enable or disable debug functions.  If enabled, you
 | |
|  *   will get the interrupt but you may or may not get a breakpoint.
 | |
|  * - Bits 2 and 1 decide whether you also get a breakpoint in addition
 | |
|  *   to an interrupt.
 | |
|  *
 | |
|  * The debug unit can do these actions in response to either internally
 | |
|  * detected breakpoint conditions from the comparators, or in response
 | |
|  * to the external breakpoint pin, or both.
 | |
|  * - Bits 14 and 1 perform the above-described functions for
 | |
|  *   internally-generated conditions, i.e., the debug comparators.
 | |
|  * - Bits 0 and 2 perform the above-described functions for external
 | |
|  *   conditions, i.e., the breakpoint external pin.
 | |
|  *
 | |
|  * Note that, although you "always" get the interrupt when you turn
 | |
|  * the debug functions, the interrupt can nevertheless, if desired, be
 | |
|  * masked by the corresponding bit in the PTD's IMR. Note also that
 | |
|  * this means that bits 14 and 0 must enable debug functions before
 | |
|  * bits 1 and 2, respectively, have any effect.
 | |
|  *
 | |
|  * NOTE: It's extremely important to not pause more than one DMA channel
 | |
|  *  at a time.
 | |
|  ********************************************************************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_pauseDma
 | |
|  * Purpose:     Pauses the DMA on a given channel (if any DMA is running
 | |
|  *              on that channel).
 | |
|  * Arguments:   channel
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  */
 | |
| int MCD_pauseDma(int channel)
 | |
| {
 | |
| 	/* MCD_XferProg progRep; */
 | |
| 
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN) {
 | |
| 		MCD_dmaBar->debugComp1 = channel;
 | |
| 		MCD_dmaBar->debugControl =
 | |
| 		    DBG_CTL_ENABLE | (1 << (channel + 16));
 | |
| 		MCD_chStatus[channel] = MCD_PAUSED;
 | |
| 
 | |
| 		/*
 | |
| 		 * Update the current buffer descriptor's lastDestAddr field
 | |
| 		 *
 | |
| 		 * MCD_XferProgrQuery (channel, &progRep);
 | |
| 		 * progRep.currBufDesc->lastDestAddr = progRep.lastDestAddr;
 | |
| 		 */
 | |
| 	}
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /************************* End of MCD_pauseDma() ********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_resumeDma
 | |
|  * Purpose:     Resumes the DMA on a given channel (if any DMA is
 | |
|  *              running on that channel).
 | |
|  * Arguments:   channel - channel on which to resume DMA
 | |
|  * Returns:     MCD_CHANNEL_INVALID if channel is invalid, else MCD_OK
 | |
|  */
 | |
| int MCD_resumeDma(int channel)
 | |
| {
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	if (MCD_dmaBar->taskControl[channel] & TASK_CTL_EN)
 | |
| 		MCD_resmActions(channel);
 | |
| 
 | |
| 	return (MCD_OK);
 | |
| }
 | |
| 
 | |
| /************************ End of MCD_resumeDma() ********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_csumQuery
 | |
|  * Purpose:     Provide the checksum after performing a non-chained DMA
 | |
|  * Arguments:   channel - channel to report on
 | |
|  *              csum - pointer to where to write the checksum/CRC
 | |
|  * Returns:     MCD_ERROR if the channel is invalid, else MCD_OK
 | |
|  *
 | |
|  * Notes:
 | |
|  *
 | |
|  */
 | |
| int MCD_csumQuery(int channel, u32 * csum)
 | |
| {
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 	if ((channel < 0) || (channel >= NCHANNELS))
 | |
| 		return (MCD_CHANNEL_INVALID);
 | |
| 
 | |
| 	*csum = MCD_relocBuffDesc[channel].csumResult;
 | |
| 	return (MCD_OK);
 | |
| #else
 | |
| 	return (MCD_ERROR);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*********************** End of MCD_resumeDma() *********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_getCodeSize
 | |
|  * Purpose:     Provide the size requirements of the microcoded tasks
 | |
|  * Returns:     Size in bytes
 | |
|  */
 | |
| int MCD_getCodeSize(void)
 | |
| {
 | |
| #ifdef MCD_INCLUDE_EU
 | |
| 	return (0x2b5c);
 | |
| #else
 | |
| 	return (0x173c);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /********************** End of MCD_getCodeSize() ********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Function:    MCD_getVersion
 | |
|  * Purpose:     Provide the version string and number
 | |
|  * Arguments:   longVersion - user supplied pointer to a pointer to a char
 | |
|  *                    which points to the version string
 | |
|  * Returns:     Version number and version string (by reference)
 | |
|  */
 | |
| char MCD_versionString[] = "Multi-channel DMA API Alpha v0.3 (2004-04-26)";
 | |
| #define MCD_REV_MAJOR   0x00
 | |
| #define MCD_REV_MINOR   0x03
 | |
| 
 | |
| int MCD_getVersion(char **longVersion)
 | |
| {
 | |
| 	*longVersion = MCD_versionString;
 | |
| 	return ((MCD_REV_MAJOR << 8) | MCD_REV_MINOR);
 | |
| }
 | |
| 
 | |
| /********************** End of MCD_getVersion() *********************/
 | |
| 
 | |
| /********************************************************************/
 | |
| /* Private version of memcpy()
 | |
|  * Note that everything this is used for is longword-aligned.
 | |
|  */
 | |
| static void MCD_memcpy(int *dest, int *src, u32 size)
 | |
| {
 | |
| 	u32 i;
 | |
| 
 | |
| 	for (i = 0; i < size; i += sizeof(int), dest++, src++)
 | |
| 		*dest = *src;
 | |
| }
 |