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 */ 16 dmaRegs *MCD_dmaBar; 17 18 /* 19 * These are the real and model task tables as generated by the 20 * build process 21 */ 22 extern TaskTableEntry MCD_realTaskTableSrc[NCHANNELS]; 23 extern 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 */ 29 volatile TaskTableEntry *MCD_taskTable; 30 TaskTableEntry *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 */ 37 static 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 */ 45 static void MCD_memcpy(int *dest, int *src, u32 size); 46 static 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 54 extern MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; 55 #else 56 MCD_bufDesc MCD_singleBufDescs[NCHANNELS]; 57 #endif 58 MCD_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 */ 103 typedef struct MCD_remVariants_struct MCD_remVariant; 104 struct 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 */ 113 MCD_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 */ 127 extern u32 MCD_funcDescTab0[]; 128 129 int 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 */ 308 int 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 359 int 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 622 int 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 */ 776 static 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 */ 804 int 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 */ 843 int 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 */ 895 int 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 */ 927 int 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 */ 950 int 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 */ 970 int 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 */ 988 char 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 992 int 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 */ 1004 static 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