1 /************************************************************
3 * copyright @ Motorola, 1999
7 * App. API are the APIs Kernel provides for the application
10 ************************************************************/
11 #include "dma_export.h"
14 /* Define a macro to use an optional application-layer print function, if
15 * one was passed to the library during initialization. If there was no
16 * function pointer passed, this protects against referencing a NULL pointer.
17 * Also define The global variable that holds the passed pointer.
19 #define PRINT if ( app_print ) app_print
20 static int (*app_print)(char *,...);
22 /* Set by call to get_eumbbar during DMA_Initialize.
23 * This could be globally available to the library, but there is
24 * an advantage to passing it as a parameter: it is already in a register
25 * and doesn't have to be loaded from memory. Also, that is the way the
26 * library was already implemented and I don't want to change it without
27 * a more detailed analysis.
28 * It is being set as a global variable during initialization to hide it from
29 * the DINK application layer, because it is Kahlua-specific. I think that
30 * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in
31 * a Kahlua-specific library dealing with the embedded utilities memory block.
32 * Right now, get_eumbbar is defined in dink32/kahlua.s. The other two are
33 * defined in dink32/drivers/i2c/i2c2.s, drivers/dma/dma2.s, etc.
35 static unsigned int Global_eumbbar = 0;
36 extern unsigned int get_eumbbar();
39 extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg );
40 #pragma Alias( load_runtime_reg, "load_runtime_reg" );
42 extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val );
43 #pragma Alias( store_runtime_reg, "store_runtime_reg" );
45 unsigned int dma_reg_tb[][14] = {
46 /* local DMA registers */
48 /* DMA_0_MR */ 0x00001100,
49 /* DMA_0_SR */ 0x00001104,
50 /* DMA_0_CDAR */ 0x00001108,
51 /* DMA_0_SAR */ 0x00001110,
52 /* DMA_0_DAR */ 0x00001118,
53 /* DMA_0_BCR */ 0x00001120,
54 /* DMA_0_NDAR */ 0x00001124,
55 /* DMA_1_MR */ 0x00001200,
56 /* DMA_1_SR */ 0x00001204,
57 /* DMA_1_CDAR */ 0x00001208,
58 /* DMA_1_SAR */ 0x00001210,
59 /* DMA_1_DAR */ 0x00001218,
60 /* DMA_1_BCR */ 0x00001220,
61 /* DMA_1_NDAR */ 0x00001224,
63 /* remote DMA registers */
65 /* DMA_0_MR */ 0x00000100,
66 /* DMA_0_SR */ 0x00000104,
67 /* DMA_0_CDAR */ 0x00000108,
68 /* DMA_0_SAR */ 0x00000110,
69 /* DMA_0_DAR */ 0x00000118,
70 /* DMA_0_BCR */ 0x00000120,
71 /* DMA_0_NDAR */ 0x00000124,
72 /* DMA_1_MR */ 0x00000200,
73 /* DMA_1_SR */ 0x00000204,
74 /* DMA_1_CDAR */ 0x00000208,
75 /* DMA_1_SAR */ 0x00000210,
76 /* DMA_1_DAR */ 0x00000218,
77 /* DMA_1_BCR */ 0x00000220,
78 /* DMA_1_NDAR */ 0x00000224,
84 /* Initialize DMA unit with the following:
85 * optional pointer to application layer print function
87 * These parameters may be added:
89 * Interrupt enables, modes, etc. are set for each transfer.
91 * This function must be called before DMA unit can be used.
94 DMA_Status DMA_Initialize( int (*p)(char *,...))
97 /* establish the pointer, if there is one, to the application's "printf" */
100 /* If this is the first call, get the embedded utilities memory block
101 * base address. I'm not sure what to do about error handling here:
102 * if a non-zero value is returned, accept it.
104 if ( Global_eumbbar == 0)
105 Global_eumbbar = get_eumbbar();
106 if ( Global_eumbbar == 0)
108 PRINT( "DMA_Initialize: can't find EUMBBAR\n" );
116 /* Perform the DMA transfer, only direct mode is currently implemented.
117 * At this point, I think it would be better to define a different
118 * function for chaining mode.
119 * Also, I'm not sure if it is appropriate to have the "generic" API
120 * accept snoop and int_steer parameters. The DINK user interface allows
121 * them, so for now I'll leave them.
123 * int_steer controls DMA interrupt steering to PCI or local processor
124 * type is the type of transfer: M2M, M2P, P2M, P2P
125 * source is the source address of the data
126 * dest is the destination address of the data
127 * len is the length of data to transfer
128 * channel is the DMA channel to use for the transfer
129 * snoop is the snoop enable control
131 extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer,
132 DMA_TRANSFER_TYPE type,
137 DMA_SNOOP_MODE snoop)
141 /* it's inappropriate for curr to be a struct, but I'll leave it */
146 /* The rest of this code was moved from device.c test_dma to here.
147 * It needs to be cleaned up and validated, but at least it is removed
148 * from the application and API. Most of the mode is left hard coded.
149 * This should be changed after the final API is defined and the user
150 * application has a way to control the transfer.
154 if ( DMA_Get_Mode( LOCAL, Global_eumbbar, channel, &md ) != DMASUCCESS )
161 md.dahts = 3; /* 8 - byte */
162 md.sahts = 3; /* 8 - byte */
166 /* if steering interrupts to local processor, use polling mode */
167 if ( int_steer == DMA_INT_STEER_PCI )
176 md.ctm = 1; /* direct mode */
179 /* validate the length range */
180 if (len > 0x3ffffff )
182 PRINT( "dev DMA: length of transfer too large: %d\n", len );
186 /* inappropriate to use a struct, but leave as is for now */
187 curr.src_addr = source;
188 curr.dest_addr = dest;
191 (void)DMA_Poke_Desp( LOCAL, Global_eumbbar, channel, &cdar );
195 if ( ( stat = DMA_Bld_Desp( LOCAL, Global_eumbbar, channel, cdar ))
197 ( stat = DMA_Bld_Curr( LOCAL, Global_eumbbar, channel, curr ))
199 ( stat = DMA_Set_Mode( LOCAL, Global_eumbbar, channel, md ))
201 ( stat = DMA_Start( LOCAL, Global_eumbbar, channel ))
204 if ( stat == DMACHNBUSY )
206 PRINT( "dev DMA: channel %d busy.\n", channel );
210 PRINT( "dev DMA: invalid channel request.\n", channel );
216 /* Since we are interested at the DMA performace right now,
217 we are going to do as less as possible to burden the
220 if you have epic enabled or don't care the return from
221 DMA operation, you can just return SUCCESS.
223 if you don't have epic enabled and care the DMA result,
224 you can use the polling method below.
226 Note: I'll attempt to activate the code for handling polling.
230 /* if steering interrupt to local processor, let it handle results */
231 if ( int_steer == DMA_INT_STEER_LOCAL )
236 /* polling since interrupt goes to PCI */
239 stat = DMA_ISR( Global_eumbbar, channel, dma_error_func,
240 dma_error_func, dma_error_func, dma_error_func );
242 while ( stat == DMANOEVENT );
248 /* DMA library internal functions */
253 * In all following functions, the host (KAHLUA) processor has a
254 * choice of accessing on board local DMA (LOCAL),
255 * or DMA on a distributed KAHLUA (REMOTE). In either case,
256 * the caller shall pass the configured embedded utility memory
257 * block base address relative to the DMA. If LOCAL DMA is used,
258 * this parameter shall be EUMBBAR, if REMOTE is used, the
259 * parameter shall be the corresponding PCSRBAR.
262 /**************************************************************
263 * function: DMA_Get_Stat
265 * description: return the content of status register of
266 * the given DMA channel
268 * if error, reserved0 field all 1s.
269 **************************************************************/
271 DMAStatus DMA_Get_Stat( LOCATION host, unsigned int eumbbar, unsigned int channel, DMA_SR *stat )
275 if ( channel != 0 && channel != 1 || stat == 0 )
280 tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG] );
282 PRINT( "%s(%d): %s DMA %d (0x%08x) stat = 0x%08x\n", __FILE__, __LINE__,
283 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG], tmp );
286 stat->reserved0 = ( tmp & 0xffffff00 ) >> 8;
287 stat->lme = ( tmp & 0x00000080 ) >> 7;
288 stat->reserved1 = ( tmp & 0x00000060 ) >> 5;
289 stat->pe = ( tmp & 0x00000010 ) >> 4;
290 stat->reserved2 = ( tmp & 0x00000008 ) >> 3;
291 stat->cb = ( tmp & 0x00000004 ) >> 2;
292 stat->eosi = ( tmp & 0x00000002 ) >> 1;
293 stat->eocai = ( tmp & 0x00000001 );
298 /**************************************************************
299 * function: DMA_Get_Mode
301 * description: return the content of mode register of the
304 * if error, return DMAINVALID, otherwise return
306 **************************************************************/
308 DMAStatus DMA_Get_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR *mode )
311 if ( channel != 0 && channel != 1 || mode == 0 )
316 tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG] );
319 PRINT( "%s(%d): %s DMA %d (0x%08x) mode = 0x%08x\n", __FILE__, __LINE__,
320 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG], tmp );
323 mode->reserved0 = (tmp & 0xfff00000) >> 20;
324 mode->irqs = (tmp & 0x00080000) >> 19;
325 mode->pde = (tmp & 0x00040000) >> 18;
326 mode->dahts = (tmp & 0x00030000) >> 16;
327 mode->sahts = (tmp & 0x0000c000) >> 14;
328 mode->dahe = (tmp & 0x00002000) >> 13;
329 mode->sahe = (tmp & 0x00001000) >> 12;
330 mode->prc = (tmp & 0x00000c00) >> 10;
331 mode->reserved1 = (tmp & 0x00000200) >> 9;
332 mode->eie = (tmp & 0x00000100) >> 8;
333 mode->eotie = (tmp & 0x00000080) >> 7;
334 mode->reserved2 = (tmp & 0x00000070) >> 4;
335 mode->dl = (tmp & 0x00000008) >> 3;
336 mode->ctm = (tmp & 0x00000004) >> 2;
337 mode->cc = (tmp & 0x00000002) >> 1;
338 mode->cs = (tmp & 0x00000001);
343 /**************************************************************
344 * function: DMA_Set_Mode
346 * description: Set a new mode to a given DMA channel
348 * note: It is not a good idea of changing the DMA mode during
349 * the middle of a transaction.
350 **************************************************************/
352 DMAStatus DMA_Set_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR mode )
355 if ( channel != 0 && channel != 1 )
360 tmp = ( mode.reserved0 & 0xfff ) << 20;
361 tmp |= ( ( mode.irqs & 0x1 ) << 19);
362 tmp |= ( ( mode.pde & 0x1 ) << 18 );
363 tmp |= ( ( mode.dahts & 0x3 ) << 16 );
364 tmp |= ( ( mode.sahts & 0x3 ) << 14 );
365 tmp |= ( ( mode.dahe & 0x1 ) << 13 );
366 tmp |= ( ( mode.sahe & 0x1 ) << 12 );
367 tmp |= ( ( mode.prc & 0x3 ) << 10 );
368 tmp |= ( ( mode.reserved1 & 0x1 ) << 9 );
369 tmp |= ( ( mode.eie & 0x1 ) << 8 );
370 tmp |= ( ( mode.eotie & 0x1 ) << 7 );
371 tmp |= ( ( mode.reserved2 & 0x7 ) << 4 );
372 tmp |= ( ( mode.dl & 0x1 ) << 3 );
373 tmp |= ( ( mode.ctm & 0x1 ) << 2 );
374 tmp |= ( ( mode.cc & 0x1 ) << 1 ) ;
375 tmp |= ( mode.cs & 0x1 );
377 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], tmp );
381 /************************************************************
382 * function: DMA_Start
384 * description: start a given DMA channel transaction
385 * return DMASUCCESS if success otherwise return
388 * note: this function will clear DMA_MR(CC) first, then
390 ***********************************************************/
392 DMAStatus DMA_Start( LOCATION host, unsigned int eumbbar, unsigned int channel )
397 if ( channel != 0 && channel != 1 )
402 if ( DMA_Get_Stat( host, eumbbar, channel, &stat ) != DMASUCCESS )
409 /* DMA is not free */
413 mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG] );
414 /* clear DMA_MR(CS) */
416 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
420 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
424 /***********************************************************
427 * description: halt the current dma transaction on the specified
429 * return DMASUCCESS if success otherwise return DMAINVALID
431 * note: if the specified DMA channel is idle, nothing happens
432 *************************************************************/
434 DMAStatus DMA_Halt( LOCATION host, unsigned int eumbbar, unsigned int channel )
437 if ( channel != 0 && channel != 1 )
442 mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG]);
444 /* clear DMA_MR(CS) */
446 store_runtime_reg(eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode );
450 /*************************************************************
451 * function: DMA_Chn_Cnt
453 * description: set the DMA_MR(CC) bit for a given channel
454 * that is in chaining mode.
455 * return DMASUCCESS if successfule, otherwise return
458 * note: if the given channel is not in chaining mode, nothing
461 *************************************************************/
463 DMAStatus DMA_Chn_Cnt( LOCATION host, unsigned int eumbbar, unsigned int channel )
466 if ( channel != 0 && channel != 1 )
471 if ( DMA_Get_Mode( host, eumbbar, channel, &mode ) != DMASUCCESS )
478 /* either illegal mode or not chaining mode */
483 return DMA_Set_Mode( host, eumbbar, channel, mode );
486 /**************************************************************
487 * function: DMA_Bld_Desp
489 * description: set current descriptor address register
490 * according to the desp for a given channel
492 * if the given channel is busy return DMACHNBUSY
493 * and no change made, otherwise return DMASUCCESS.
496 **************************************************************/
498 DMAStatus DMA_Bld_Desp( LOCATION host,
499 unsigned int eumbbar,
500 unsigned int channel,
506 if ( channel != 0 && channel != 1 )
508 /* channel number out of range */
512 if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
517 if ( status.cb == 1 )
523 temp = ( desp.cda & 0x7ffffff ) << 5;
524 temp |= (( desp.snen & 0x1 ) << 4 );
525 temp |= (( desp.eosie & 0x1 ) << 3 );
526 temp |= (( desp.ctt & 0x3 ) << 1 );
527 temp |= ( desp.eotd & 0x1 );
529 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
532 PRINT( "%s(%d): %s DMA %d (0x%08x) cdar := 0x%08x\n", __FILE__, __LINE__,
533 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp );
539 /**************************************************************
540 * function: DMA_Poke_Desp
542 * description: poke the current descriptor address register
543 * for a given channel
545 * return DMASUCCESS if no error
547 * note: Due to the undeterministic parallellism of DMA operation,
548 * the value returned by this function shall be taken as
549 * the most recently used descriptor when the last time
550 * DMA starts a chaining mode operation.
551 **************************************************************/
553 DMAStatus DMA_Poke_Desp( LOCATION host,
554 unsigned int eumbbar,
555 unsigned int channel,
559 if ( channel != 0 && channel != 1 || desp == 0 )
564 cdar = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG] );
567 PRINT( "%s(%d): %s DMA %d (0x%08x) cdar : 0x%08x\n", __FILE__, __LINE__,
568 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], cdar );
572 desp->cda = ( cdar & 0xffffffe0 ) >> 5;
573 desp->snen = ( cdar & 0x00000010 ) >> 4;
574 desp->eosie = ( cdar & 0x00000008 ) >> 3;
575 desp->ctt = ( cdar & 0x00000006 ) >> 1;
576 desp->eotd = ( cdar & 0x00000001 );
581 /**************************************************************
582 * function: DMA_Bld_Curr
584 * description: set current src, dest, byte count registers
585 * according to the desp for a given channel
586 * return DMASUCCESS if no error.
589 **************************************************************/
591 DMAStatus DMA_Bld_Curr( LOCATION host,
592 unsigned int eumbbar,
593 unsigned int channel,
597 if ( channel != 0 && channel != 1 )
599 /* channel number out of range */
603 if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS )
608 if ( status.cb == 1 )
614 desp.byte_cnt &= 0x03ffffff; /* upper 6-bits are 0s */
616 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG], desp.src_addr );
618 PRINT( "%s(%d): %s DMA %d (0x%08x) src := 0x%08x\n", __FILE__, __LINE__,
619 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.src_addr );
622 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG], desp.dest_addr );
624 PRINT( "%s(%d): %s DMA %d (0x%08x) dest := 0x%08x\n", __FILE__, __LINE__,
625 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.dest_addr );
628 store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG], desp.byte_cnt );
630 PRINT( "%s(%d): %s DMA %d (0x%08x) count := 0x%08x\n", __FILE__, __LINE__,
631 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.byte_cnt );
639 /**************************************************************
640 * function: DMA_Poke_Curr
642 * description: poke the current src, dest, byte count registers
643 * for a given channel.
645 * return DMASUCCESS if no error
647 * note: Due to the undeterministic parallelism, in chaining
648 * mode, the value returned by this function shall
649 * be taken as reference when the query is made rather
650 * than the absolute snapshot when the value is returned.
651 **************************************************************/
653 DMAStatus DMA_Poke_Curr( LOCATION host,
654 unsigned int eumbbar,
655 unsigned int channel,
658 if ( channel != 0 && channel != 1 || desp == 0 )
663 desp->src_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG] );
665 PRINT( "%s(%d): %s DMA %d (0x%08x) src : 0x%08x\n", __FILE__, __LINE__,
666 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->src_addr );
669 desp->dest_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG] );
671 PRINT( "%s(%d): %s DMA %d (0x%08x) dest : 0x%08x\n", __FILE__, __LINE__,
672 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->dest_addr );
675 desp->byte_cnt = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG] );
677 PRINT( "%s(%d): %s DMA %d (0x%08x) count : 0x%08x\n", __FILE__, __LINE__,
678 ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->byte_cnt );
685 /*****************************************************************
686 * function: dma_error_func
688 * description: display the error information
690 * note: This seems like a highly convoluted way to handle messages,
691 * but I'll leave it as it was in device.c when I moved it into the
692 * DMA library source.
693 ****************************************************************/
695 DMAStatus dma_error_func( unsigned int eumbbar, unsigned int chn, DMAStatus err)
697 unsigned char *msg[] =
699 "Local Memory Error",
702 "End-of-Segment Interrupt",
703 "End-of-Chain/Direct Interrupt",
706 if ( err >= DMALMERROR && err <= DMAEOCAINT )
708 PRINT( "DMA Status: channel %d %s\n", chn, msg[err-DMASUCCESS-1] );
715 /*************************************************************
718 * description: DMA interrupt service routine
719 * return DMAStatus value based on
722 *************************************************************/
724 DMAStatus DMA_ISR( unsigned int eumbbar,
725 unsigned int channel,
726 DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ),
727 DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ),
728 DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ),
729 DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus ))
733 DMAStatus rval = DMANOEVENT;
736 if ( channel != 0 && channel != 1 )
741 if ( DMA_Get_Stat( LOCAL, eumbbar, channel, &stat ) != DMASUCCESS )
748 /* local memory error */
752 rval = (*lme_func)(eumbbar, channel, DMALMERROR );
756 else if ( stat.pe == 1 )
762 rval = (*pe_func)(eumbbar, channel, DMAPERROR );
766 else if ( stat.eosi == 1 )
768 /* end-of-segment interrupt */
770 if ( eosi_func != 0 )
772 rval = (*eosi_func)(eumbbar, channel, DMAEOSINT );
777 /* End-of-chain/direct interrupt */
779 if ( eocai_func != 0 )
781 rval = (*eocai_func)(eumbbar, channel, DMAEOCAINT );
785 temp = ( stat.reserved0 & 0xffffff ) << 8;
786 temp |= ( ( stat.lme & 0x1 ) << 7 ); /* write one to clear */
787 temp |= ( ( stat.reserved1 & 0x3 ) << 5 );
788 temp |= ( ( stat.pe & 0x1 ) << 4 ); /* write one to clear */
789 temp |= ( ( stat.reserved2 & 0x1 ) << 3 );
790 temp |= ( ( stat.cb & 0x1 ) << 2 ); /* write one to clear */
791 temp |= ( ( stat.eosi & 0x1 ) << 1 ); /* write one to clear */
792 temp |= ( stat.eocai & 0x1 ); /* write one to clear */
794 store_runtime_reg( eumbbar, dma_reg_tb[LOCAL][channel*NUM_DMA_REG + DMA_SR_REG], temp );
797 PRINT( "%s(%d): DMA channel %d SR := 0x%08x\n", __FILE__, __LINE__, channel, temp );