|
@@ -0,0 +1,1026 @@
|
|
|
+/*
|
|
|
+ * 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>
|
|
|
+
|
|
|
+#ifdef CONFIG_FSLDMAFEC
|
|
|
+
|
|
|
+#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(srcAddr, srcAddr, 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(srcAddr, srcAddr, 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(srcAddr, srcIncr, destAddr,
|
|
|
+ destIncr, 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(srcAddr, srcIncr, destAddr,
|
|
|
+ destIncr, 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;
|
|
|
+}
|
|
|
+#endif /* CONFIG_FSLDMAFEC */
|