MCD_dmaApi.c 35 KB

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