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