Root/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/m547x/MCD_dmaApi.c

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

Archive Download this file



interactive