📄 mcd_dmaapi.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>#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_EUextern MCD_bufDesc MCD_singleBufDescs[NCHANNELS];#elseMCD_bufDesc MCD_singleBufDescs[NCHANNELS];#endifMCD_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -