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 */ 17 dmaRegs *MCD_dmaBar; 18 19 /* 20 * These are the real and model task tables as generated by the 21 * build process 22 */ 23 extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS]; 24 extern 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 */ 30 volatile TaskTableEntry *MCD_taskTable; 31 TaskTableEntry *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 */ 38 static 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 */ 46 static void MCD_memcpy(int *dest, int *src, u32 size); 47 static 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 55 extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; 56 #else 57 MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; 58 #endif 59 MCD_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 */ 104 typedef struct MCD_remVariants_struct MCD_remVariant; 105 struct 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 */ 114 MCD_remVariant MCD_remVariants; 115 /********************************************************************/ 116 /* Function: MCD_initDma 117 * Purpose: Initializes the DMA API by setting up a pointer to the DMA 118 * registers, relocating and creating the appropriate task 119 * structures, and setting up some global settings 120 * Arguments: 121 * dmaBarAddr - pointer to the multichannel DMA registers 122 * taskTableDest - location to move DMA task code and structs to 123 * flags - operational parameters 124 * Return Value: 125 * MCD_TABLE_UNALIGNED if taskTableDest is not 512-byte aligned 126 * MCD_OK otherwise 127 */ 128 extern u32 MCD_funcDescTab0[]; 129 130 int 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 */ 309 int 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 360 int 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 623 int 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 */ 777 static 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 */ 805 int 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 */ 844 int 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 */ 896 int 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 */ 928 int 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 */ 951 int 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 */ 971 int 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 */ 989 char 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 993 int 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 */ 1005 static 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