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