]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/dmaps_v2_0/src/xdmaps.c
b20b909afe76ac1d979e536995d0f437bc65318a
[freertos] / FreeRTOS / Demo / CORTEX_A9_Zynq_ZC702 / RTOSDemo_bsp / ps7_cortexa9_0 / libsrc / dmaps_v2_0 / src / xdmaps.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal 
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /****************************************************************************/
33 /**
34 *
35 * @file xdmaps.c
36 * @addtogroup dmaps_v2_0
37 * @{
38 *
39 * This file contains the implementation of the interface functions for XDmaPs
40 * driver. Refer to the header file xdmaps.h for more detailed information.
41 *
42 * <pre>
43 * MODIFICATION HISTORY:
44 *
45 * Ver   Who     Date     Changes
46 * ----- ------ -------- ----------------------------------------------
47 * 1.00  hbm    08/19/2010 First Release
48 * 1.00  nm     05/25/2011 Updated for minor doxygen corrections
49 * 1.02a sg     05/16/2012 Made changes for doxygen and moved some function
50 *                         header from the xdmaps.h file to xdmaps.c file
51 *                         Other cleanup for coding guidelines and CR 657109
52 *                         and CR 657898
53 * 1.03a sg     07/16/2012 changed inline to __inline for CR665681
54 * 1.04a nm     10/22/2012 Fixed CR# 681671.
55 * 1.05a nm     04/15/2013 Fixed CR# 704396. Removed warnings when compiled
56 *                         with -Wall and -Wextra option in bsp.
57 *              05/01/2013 Fixed CR# 700189. Changed XDmaPs_BuildDmaProg()
58 *                         function description.
59 *                         Fixed CR# 704396. Removed unused variables
60 *                         UseM2MByte & MemBurstLen from XDmaPs_BuildDmaProg()
61 *                         function.
62 * 1.07a asa    11/02/13. Made changes to fix compilation issues for iarcc.
63 *                          Removed the PDBG prints. By default they were always
64 *                          defined out and never used. The PDBG is non-standard for
65 *                          Xilinx drivers and no other driver does something similar.
66 *                          Since there is no easy way to fix compilation issues with
67 *                          the IARCC compiler around PDBG, it is better to remove it.
68 *                          Users can always use xil_printfs if they want to debug.
69 * </pre>
70 *
71 *****************************************************************************/
72
73 /***************************** Include Files ********************************/
74
75 #include <string.h>
76
77 #include "xstatus.h"
78 #include "xdmaps.h"
79 #include "xil_io.h"
80 #include "xil_cache.h"
81
82 #include "xil_printf.h"
83
84
85 /************************** Constant Definitions ****************************/
86
87 /* The following constant defines the amount of error that is allowed for
88  * a specified baud rate. This error is the difference between the actual
89  * baud rate that will be generated using the specified clock and the
90  * desired baud rate.
91  */
92
93 /**************************** Type Definitions ******************************/
94
95 /***************** Macros (Inline Functions) Definitions ********************/
96
97
98 /************************** Function Prototypes *****************************/
99 static int XDmaPs_Exec_DMAKILL(u32 BaseAddr,
100                                 unsigned int Channel,
101                                 unsigned int Thread);
102
103 static void XDmaPs_BufPool_Free(XDmaPs_ProgBuf *Pool, void *Buf);
104
105 static int XDmaPs_Exec_DMAGO(u32 BaseAddr, unsigned int Channel, u32 DmaProg);
106
107 static void XDmaPs_DoneISR_n(XDmaPs *InstPtr, unsigned Channel);
108 static void *XDmaPs_BufPool_Allocate(XDmaPs_ProgBuf *Pool);
109 static int XDmaPs_BuildDmaProg(unsigned Channel, XDmaPs_Cmd *Cmd,
110                                 unsigned CacheLength);
111
112 static void XDmaPs_Print_DmaProgBuf(char *Buf, int Length);
113
114
115
116 /************************** Variable Definitions ****************************/
117
118 /****************************************************************************/
119 /**
120 *
121 * Initializes a specific XDmaPs instance such that it is ready to be used.
122 * The data format of the device is setup for 8 data bits, 1 stop bit, and no
123 * parity by default. The baud rate is set to a default value specified by
124 * Config->DefaultBaudRate if set, otherwise it is set to 19.2K baud. The
125 * receive FIFO threshold is set for 8 bytes. The default operating mode of the
126 * driver is polled mode.
127 *
128 * @param        InstPtr is a pointer to the XDmaPs instance.
129 * @param        Config is a reference to a structure containing information
130 *               about a specific XDmaPs driver.
131 * @param        EffectiveAddr is the device base address in the virtual memory
132 *               address space. The caller is responsible for keeping the
133 *               address mapping from EffectiveAddr to the device physical base
134 *               address unchanged once this function is invoked. Unexpected
135 *               errors may occur if the address mapping changes after this
136 *               function is called. If address translation is not used, pass in
137 *               the physical address instead.
138 *
139 * @return
140 *
141 *               - XST_SUCCESS on initialization completion
142 *
143 * @note         None.
144 *
145 *****************************************************************************/
146 int XDmaPs_CfgInitialize(XDmaPs *InstPtr,
147                           XDmaPs_Config *Config,
148                           u32 EffectiveAddr)
149 {
150         int Status = XST_SUCCESS;
151         unsigned int CacheLength = 0;
152         u32 CfgReg;
153         unsigned Channel;
154         XDmaPs_ChannelData *ChanData;
155
156         /*
157          * Assert validates the input arguments
158          */
159         Xil_AssertNonvoid(InstPtr != NULL);
160         Xil_AssertNonvoid(Config != NULL);
161
162         /*
163          * Setup the driver instance using passed in parameters
164          */
165         InstPtr->Config.DeviceId = Config->DeviceId;
166         InstPtr->Config.BaseAddress = EffectiveAddr;
167
168         CfgReg = XDmaPs_ReadReg(EffectiveAddr, XDMAPS_CR1_OFFSET);
169         CacheLength = CfgReg & XDMAPS_CR1_I_CACHE_LEN_MASK;
170         if (CacheLength < 2 || CacheLength > 5)
171                 CacheLength = 0;
172         else
173                 CacheLength = 1 << CacheLength;
174
175         InstPtr->CacheLength = CacheLength;
176
177         memset(InstPtr->Chans, 0,
178                sizeof(XDmaPs_ChannelData[XDMAPS_CHANNELS_PER_DEV]));
179
180         for (Channel = 0; Channel < XDMAPS_CHANNELS_PER_DEV; Channel++) {
181                 ChanData = InstPtr->Chans + Channel;
182                 ChanData->ChanId = Channel;
183                 ChanData->DevId = Config->DeviceId;
184         }
185
186         InstPtr->IsReady = 1;
187
188         return Status;
189 }
190
191 /****************************************************************************/
192 /**
193 *
194 * Reset the DMA Manager.
195 *
196 * @param        InstPtr is the DMA instance.
197 *
198 * @return       0 on success, -1 on time out
199 *
200 * @note         None.
201 *
202 *****************************************************************************/
203 int XDmaPs_ResetManager(XDmaPs *InstPtr)
204 {
205         int Status;
206         Status = XDmaPs_Exec_DMAKILL(InstPtr->Config.BaseAddress,
207                                       0, 0);
208
209         return Status;
210 }
211
212 /****************************************************************************/
213 /**
214 *
215 * Reset the specified DMA Channel.
216 *
217 * @param        InstPtr is the DMA instance.
218 * @param        Channel is the channel to be reset.
219 *
220 * @return       0 on success, -1 on time out
221 *
222 * @note         None.
223 *
224 *****************************************************************************/
225 int XDmaPs_ResetChannel(XDmaPs *InstPtr, unsigned int Channel)
226 {
227         int Status;
228         Status = XDmaPs_Exec_DMAKILL(InstPtr->Config.BaseAddress,
229                                       Channel, 1);
230
231         return Status;
232
233 }
234
235 /*****************************************************************************/
236 /**
237 *
238 * Driver fault interrupt service routine
239 * This is the one that connects the GIC
240 *
241 * @param        InstPtr is the DMA instance.
242 *
243 * @return       None.
244 *
245 * @note         None.
246 *
247 ******************************************************************************/
248 void XDmaPs_FaultISR(XDmaPs *InstPtr)
249 {
250
251         void *DmaProgBuf;
252         u32 Fsm; /* Fault status DMA manager register value */
253         u32 Fsc; /* Fault status DMA channel register value */
254         u32 FaultType; /* Fault type DMA manager register value */
255
256         u32 BaseAddr = InstPtr->Config.BaseAddress;
257
258         u32 Pc; /* DMA Pc or channel Pc */
259         XDmaPs_ChannelData *ChanData;
260
261         unsigned Chan;
262         unsigned DevId;
263
264         XDmaPs_Cmd *DmaCmd;
265
266         Fsm = XDmaPs_ReadReg(BaseAddr, XDMAPS_FSM_OFFSET) & 0x01;
267         Fsc = XDmaPs_ReadReg(BaseAddr, XDMAPS_FSC_OFFSET) & 0xFF;
268
269
270         DevId = InstPtr->Config.DeviceId;
271
272         if (Fsm) {
273                 /*
274                  * if DMA manager is fault
275                  */
276                 FaultType = XDmaPs_ReadReg(BaseAddr, XDMAPS_FTM_OFFSET);
277                 Pc = XDmaPs_ReadReg(BaseAddr, XDMAPS_DPC_OFFSET);
278
279                 xil_printf("PL330 device %d fault with type: %x at Pc %x\n",
280                            DevId,
281                            FaultType, Pc);
282
283                 /* kill the DMA manager thread */
284                 /* Should we disable interrupt?*/
285                 XDmaPs_Exec_DMAKILL(BaseAddr, 0, 0);
286         }
287
288         /*
289          * check which channel faults and kill the channel thread
290          */
291         for (Chan = 0;
292              Chan < XDMAPS_CHANNELS_PER_DEV;
293              Chan++) {
294                 if (Fsc & (0x01 << Chan)) {
295                         FaultType =
296                                 XDmaPs_ReadReg(BaseAddr,
297                                                 XDmaPs_FTCn_OFFSET(Chan));
298                         Pc = XDmaPs_ReadReg(BaseAddr,
299                                              XDmaPs_CPCn_OFFSET(Chan));
300
301                         /* kill the channel thread */
302                         /* Should we disable interrupt? */
303                         XDmaPs_Exec_DMAKILL(BaseAddr, Chan, 1);
304
305                         /*
306                          * get the fault type and fault Pc and invoke the
307                          * fault callback.
308                          */
309                         ChanData = InstPtr->Chans + Chan;
310
311                         DmaCmd = ChanData->DmaCmdToHw;
312
313                         /* Should we check DmaCmd is not null */
314                         DmaCmd->DmaStatus = -1;
315                         DmaCmd->ChanFaultType = FaultType;
316                         DmaCmd->ChanFaultPCAddr = Pc;
317                         ChanData->DmaCmdFromHw = DmaCmd;
318                         ChanData->DmaCmdToHw = NULL;
319
320                         if (!ChanData->HoldDmaProg) {
321                                 DmaProgBuf = (void *)DmaCmd->GeneratedDmaProg;
322                                 if (DmaProgBuf)
323                                         XDmaPs_BufPool_Free(ChanData->ProgBufPool,
324                                                              DmaProgBuf);
325                                 DmaCmd->GeneratedDmaProg = NULL;
326                         }
327
328                         if (InstPtr->FaultHandler)
329                                 InstPtr->FaultHandler(Chan,
330                                                       DmaCmd,
331                                                       InstPtr->FaultRef);
332
333                 }
334         }
335
336 }
337
338 /*****************************************************************************/
339 /**
340 *
341 * Set the done handler for a channel.
342 *
343 * @param        InstPtr is the DMA instance.
344 * @param        Channel is the channel number.
345 * @param        DoneHandler is the done interrupt handler.
346 * @param        CallbackRef is the callback reference data.
347 *
348 * @return       None.
349 *
350 * @note         None.
351 *
352 ******************************************************************************/
353 int XDmaPs_SetDoneHandler(XDmaPs *InstPtr,
354                            unsigned Channel,
355                            XDmaPsDoneHandler DoneHandler,
356                            void *CallbackRef)
357 {
358         XDmaPs_ChannelData *ChanData;
359
360         Xil_AssertNonvoid(InstPtr != NULL);
361
362         if (Channel >= XDMAPS_CHANNELS_PER_DEV)
363                 return XST_FAILURE;
364
365
366         ChanData = InstPtr->Chans + Channel;
367
368         ChanData->DoneHandler = DoneHandler;
369         ChanData->DoneRef = CallbackRef;
370
371         return 0;
372 }
373
374 /*****************************************************************************/
375 /**
376 *
377 * Set the fault handler for a channel.
378 *
379 * @param        InstPtr is the DMA instance.
380 * @param        FaultHandler is the fault interrupt handler.
381 * @param        CallbackRef is the callback reference data.
382 *
383 * @return       None.
384 *
385 * @note         None.
386 *
387 ******************************************************************************/
388 int XDmaPs_SetFaultHandler(XDmaPs *InstPtr,
389                             XDmaPsFaultHandler FaultHandler,
390                             void *CallbackRef)
391 {
392         Xil_AssertNonvoid(InstPtr != NULL);
393
394         InstPtr->FaultHandler = FaultHandler;
395         InstPtr->FaultRef = CallbackRef;
396
397         return XST_SUCCESS;
398 }
399
400
401
402 /****************************************************************************/
403 /**
404 * Construction function for DMAEND instruction. This function fills the program
405 * buffer with the constructed instruction.
406 *
407 * @param        DmaProg the DMA program buffer, it's the starting address for
408 *               the instruction being constructed
409 *
410 * @return       The number of bytes for this instruction which is 1.
411 *
412 * @note         None.
413 *
414 *****************************************************************************/
415 __inline int XDmaPs_Instr_DMAEND(char *DmaProg)
416 {
417         /*
418          * DMAEND encoding:
419          * 7 6 5 4 3 2 1 0
420          * 0 0 0 0 0 0 0 0
421          */
422         *DmaProg = 0x0;
423
424         return 1;
425 }
426
427 __inline void XDmaPs_Memcpy4(char *Dst, char *Src)
428 {
429         *Dst = *Src;
430         *(Dst + 1) = *(Src + 1);
431         *(Dst + 2) = *(Src + 2);
432         *(Dst + 3) = *(Src + 3);
433 }
434
435 /****************************************************************************/
436 /**
437 *
438 * Construction function for DMAGO instruction. This function fills the program
439 * buffer with the constructed instruction.
440 *
441 * @param        DmaProg is the DMA program buffer, it's the starting address
442 *               for the instruction being constructed
443 * @param        Cn is the Channel number, 0 - 7
444 * @param        Imm is 32-bit immediate number written to the Channel Program
445 *               Counter.
446 * @param        Ns is Non-secure flag. If Ns is 1, the DMA channel operates in
447 *               the Non-secure state. If Ns is 0, the execution depends on the
448 *               security state of the DMA manager:
449 *               DMA manager is in the Secure state, DMA channel operates in the
450 *               Secure state.
451 *               DMA manager is in the Non-secure state, DMAC aborts.
452 *
453 * @return       The number of bytes for this instruction which is 6.
454 *
455 * @note         None
456 *
457 *****************************************************************************/
458 __inline int XDmaPs_Instr_DMAGO(char *DmaProg, unsigned int Cn,
459                                u32 Imm, unsigned int Ns)
460 {
461         /*
462          * DMAGO encoding:
463          * 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
464          *  0  0  0  0  0 |cn[2:0]| 1  0  1  0  0  0 ns  0
465          *
466          * 47 ... 16
467          *  imm[32:0]
468          */
469         *DmaProg = 0xA0 | ((Ns << 1) & 0x02);
470
471         *(DmaProg + 1) = (u8)(Cn & 0x07);
472
473         // *((u32 *)(DmaProg + 2)) = Imm;
474         XDmaPs_Memcpy4(DmaProg + 2, (char *)&Imm);
475
476         /* success */
477         return 6;
478 }
479
480 /****************************************************************************/
481 /**
482 *
483 * Construction function for DMALD instruction. This function fills the program
484 * buffer with the constructed instruction.
485 *
486 * @param        DmaProg the DMA program buffer, it's the starting address for the
487 *               instruction being constructed
488 *
489 * @return       The number of bytes for this instruction which is 1.
490 *
491 * @note         None.
492 *
493 *****************************************************************************/
494 __inline int XDmaPs_Instr_DMALD(char *DmaProg)
495 {
496         /*
497          * DMALD encoding
498          * 7 6 5 4 3 2 1  0
499          * 0 0 0 0 0 1 bs x
500          *
501          * Note: this driver doesn't support conditional load or store,
502          * so the bs bit is 0 and x bit is 0.
503          */
504         *DmaProg = 0x04;
505         return 1;
506 }
507
508 /****************************************************************************/
509 /**
510 *
511 * Construction function for DMALP instruction. This function fills the program
512 * buffer with the constructed instruction.
513 *
514 * @param        DmaProg is the DMA program buffer, it's the starting address
515 *               for the instruction being constructed
516 * @param        Lc is the Loop counter register, can either be 0 or 1.
517 * @param        LoopIterations: the number of interations, LoopInterations - 1
518 *               will be encoded in the DMALP instruction.
519 *
520 * @return       The number of bytes for this instruction which is 2.
521 *
522 * @note         None.
523 *
524 *****************************************************************************/
525 __inline int XDmaPs_Instr_DMALP(char *DmaProg, unsigned Lc,
526                                unsigned LoopIterations)
527 {
528         /*
529          * DMALP encoding
530          * 15   ...   8 7 6 5 4 3 2 1  0
531          * | iter[7:0] |0 0 1 0 0 0 lc 0
532          */
533         *DmaProg = (u8)(0x20 | ((Lc & 1) << 1));
534         *(DmaProg + 1) = (u8)(LoopIterations - 1);
535         return 2;
536 }
537
538 /****************************************************************************/
539 /**
540 *
541 * Construction function for DMALPEND instruction. This function fills the
542 * program buffer with the constructed instruction.
543 *
544 * @param        DmaProg is the DMA program buffer, it's the starting address
545 *               for the instruction being constructed
546 * @param        BodyStart is the starting address of the loop body. It is used
547 *               to calculate the bytes of backward jump.
548 * @param        Lc is the Loop counter register, can either be 0 or 1.
549 *
550 * @return       The number of bytes for this instruction which is 2.
551 *
552 * @note None.
553 *
554 *****************************************************************************/
555 __inline int XDmaPs_Instr_DMALPEND(char *DmaProg, char *BodyStart, unsigned Lc)
556 {
557         /*
558          * DMALPEND encoding
559          * 15       ...        8 7 6 5 4  3 2  1  0
560          * | backward_jump[7:0] |0 0 1 nf 1 lc bs x
561          *
562          * lc: loop counter
563          * nf is for loop forever. The driver does not support loop forever,
564          * so nf is 1.
565          * The driver does not support conditional LPEND, so bs is 0, x is 0.
566          */
567         *DmaProg = 0x38 | ((Lc & 1) << 2);
568         *(DmaProg + 1) = (u8)(DmaProg - BodyStart);
569
570         return 2;
571 }
572
573 /*
574  * Register number for the DMAMOV instruction
575  */
576 #define XDMAPS_MOV_SAR 0x0
577 #define XDMAPS_MOV_CCR 0x1
578 #define XDMAPS_MOV_DAR 0x2
579
580 /****************************************************************************/
581 /**
582 *
583 * Construction function for DMAMOV instruction. This function fills the
584 * program buffer with the constructed instruction.
585 *
586 * @param        DmaProg is the DMA program buffer, it's the starting address
587 *               for the instruction being constructed
588 * @param        Rd is the register id, 0 for SAR, 1 for CCR, and 2 for DAR
589 * @param        Imm is the 32-bit immediate number
590 *
591 * @return       The number of bytes for this instruction which is 6.
592 *
593 * @note         None.
594 *
595 *****************************************************************************/
596 __inline int XDmaPs_Instr_DMAMOV(char *DmaProg, unsigned Rd, u32 Imm)
597 {
598         /*
599          * DMAMOV encoding
600          * 15 4 3 2 1 10 ... 8 7 6 5 4 3 2 1 0
601          *  0 0 0 0 0 |rd[2:0]|1 0 1 1 1 1 0 0
602          *
603          * 47 ... 16
604          *  imm[32:0]
605          *
606          * rd: b000 for SAR, b001 CCR, b010 DAR
607          */
608         *DmaProg = 0xBC;
609         *(DmaProg + 1) = Rd & 0x7;
610         // *((u32 *)(DmaProg + 2)) = Imm;
611         XDmaPs_Memcpy4(DmaProg + 2, (char *)&Imm);
612
613         return 6;
614 }
615
616 /****************************************************************************/
617 /**
618 *
619 * Construction function for DMANOP instruction. This function fills the
620 * program buffer with the constructed instruction.
621 *
622 * @param        DmaProg is the DMA program buffer, it's the starting address
623 *               for the instruction being constructed
624 * @return       The number of bytes for this instruction which is 1.
625 *
626 * @note         None.
627 *
628 *****************************************************************************/
629 __inline int XDmaPs_Instr_DMANOP(char *DmaProg)
630 {
631         /*
632          * DMANOP encoding
633          * 7 6 5 4 3 2 1 0
634          * 0 0 0 1 1 0 0 0
635          */
636         *DmaProg = 0x18;
637         return 1;
638 }
639
640 /****************************************************************************/
641 /**
642 *
643 * Construction function for DMARMB instruction. This function fills the
644 * program buffer with the constructed instruction.
645 *
646 * @param        DmaProg is the DMA program buffer, it's the starting address
647 *               for the instruction being constructed
648 *
649 * @return       The number of bytes for this instruction which is 1.
650 *
651 * @note         None.
652 *
653 *****************************************************************************/
654 __inline int XDmaPs_Instr_DMARMB(char *DmaProg)
655 {
656         /*
657          * DMARMB encoding
658          * 7 6 5 4 3 2 1 0
659          * 0 0 0 1 0 0 1 0
660          */
661         *DmaProg = 0x12;
662         return 1;
663 }
664
665 /****************************************************************************/
666 /**
667 *
668 * Construction function for DMASEV instruction. This function fills the
669 * program buffer with the constructed instruction.
670 *
671 * @param        DmaProg is the DMA program buffer, it's the starting address
672 *               for the instruction being constructed
673 * @param        EventNumber is the Event number to signal.
674 *
675 * @return       The number of bytes for this instruction which is 2.
676 *
677 * @note         None.
678 *
679 *****************************************************************************/
680 __inline int XDmaPs_Instr_DMASEV(char *DmaProg, unsigned int EventNumber)
681 {
682         /*
683          * DMASEV encoding
684          * 15 4 3 2 1  10 9 8 7 6 5 4 3 2 1 0
685          * |event[4:0]| 0 0 0 0 0 1 1 0 1 0 0
686          */
687         *DmaProg = 0x34;
688         *(DmaProg + 1) = (u8)(EventNumber << 3);
689
690         return 2;
691 }
692
693
694 /****************************************************************************/
695 /**
696 *
697 * Construction function for DMAST instruction. This function fills the
698 * program buffer with the constructed instruction.
699 *
700 * @param        DmaProg is the DMA program buffer, it's the starting address
701 *               for the instruction being constructed
702 *
703 * @return       The number of bytes for this instruction which is 1.
704 *
705 * @note         None.
706 *
707 *****************************************************************************/
708 __inline int XDmaPs_Instr_DMAST(char *DmaProg)
709 {
710         /*
711          * DMAST encoding
712          * 7 6 5 4 3 2 1  0
713          * 0 0 0 0 1 0 bs x
714          *
715          * Note: this driver doesn't support conditional load or store,
716          * so the bs bit is 0 and x bit is 0.
717          */
718         *DmaProg = 0x08;
719         return 1;
720 }
721
722
723 /****************************************************************************/
724 /**
725 *
726 * Construction function for DMAWMB instruction. This function fills the
727 * program buffer with the constructed instruction.
728 *
729 * @param        DmaProg is the DMA program buffer, it's the starting address
730 *               for the instruction being constructed
731 *
732 * @return       The number of bytes for this instruction which is 1.
733 *
734 * @note         None.
735 *
736 *****************************************************************************/
737 __inline int XDmaPs_Instr_DMAWMB(char *DmaProg)
738 {
739         /*
740          * DMAWMB encoding
741          * 7 6 5 4 3 2 1 0
742          * 0 0 0 1 0 0 1 0
743          */
744         *DmaProg = 0x13;
745         return 1;
746 }
747
748 /****************************************************************************/
749 /**
750 *
751 * Conversion function from the endian swap size to the bit encoding of the CCR
752 *
753 * @param        EndianSwapSize is the endian swap size, in terms of bits, it
754 *               could be 8, 16, 32, 64, or 128(We are using DMA assembly syntax)
755 *
756 * @return       The endian swap size bit encoding for the CCR.
757 *
758 * @note None.
759 *
760 *****************************************************************************/
761 __inline unsigned XDmaPs_ToEndianSwapSizeBits(unsigned int EndianSwapSize)
762 {
763         switch (EndianSwapSize) {
764         case 0:
765         case 8:
766                 return 0;
767         case 16:
768                 return 1;
769         case 32:
770                 return 2;
771         case 64:
772                 return 3;
773         case 128:
774                 return 4;
775         default:
776                 return 0;
777         }
778
779 }
780
781 /****************************************************************************/
782 /**
783 *
784 * Conversion function from the burst size to the bit encoding of the CCR
785 *
786 * @param        BurstSize is the burst size. It's the data width.
787 *               In terms of bytes, it could be 1, 2, 4, 8, 16, 32, 64, or 128.
788 *               It must be no larger than the bus width.
789 *               (We are using DMA assembly syntax.)
790 *
791 * @note         None.
792 *
793 *****************************************************************************/
794 __inline unsigned XDmaPs_ToBurstSizeBits(unsigned BurstSize)
795 {
796         switch (BurstSize) {
797         case 1:
798                 return 0;
799         case 2:
800                 return 1;
801         case 4:
802                 return 2;
803         case 8:
804                 return 3;
805         case 16:
806                 return 4;
807         case 32:
808                 return 5;
809         case 64:
810                 return 6;
811         case 128:
812                 return 7;
813         default:
814                 return 0;
815         }
816 }
817
818
819 /****************************************************************************/
820 /**
821 *
822 * Conversion function from PL330 bus transfer descriptors to CCR value. All the
823 * values passed to the functions are in terms of assembly languages, not in
824 * terms of the register bit encoding.
825 *
826 * @param        ChanCtrl is the Instance of XDmaPs_ChanCtrl.
827 *
828 * @return       The 32-bit CCR value.
829 *
830 * @note         None.
831 *
832 *****************************************************************************/
833 u32 XDmaPs_ToCCRValue(XDmaPs_ChanCtrl *ChanCtrl)
834 {
835         /*
836          * Channel Control Register encoding
837          * [31:28] - endian_swap_size
838          * [27:25] - dst_cache_ctrl
839          * [24:22] - dst_prot_ctrl
840          * [21:18] - dst_burst_len
841          * [17:15] - dst_burst_size
842          * [14]    - dst_inc
843          * [13:11] - src_cache_ctrl
844          * [10:8] - src_prot_ctrl
845          * [7:4]  - src_burst_len
846          * [3:1]  - src_burst_size
847          * [0]     - src_inc
848          */
849
850         unsigned es =
851                 XDmaPs_ToEndianSwapSizeBits(ChanCtrl->EndianSwapSize);
852
853         unsigned dst_burst_size =
854                 XDmaPs_ToBurstSizeBits(ChanCtrl->DstBurstSize);
855         unsigned dst_burst_len = (ChanCtrl->DstBurstLen - 1) & 0x0F;
856         unsigned dst_cache_ctrl = (ChanCtrl->DstCacheCtrl & 0x03)
857                 | ((ChanCtrl->DstCacheCtrl & 0x08) >> 1);
858         unsigned dst_prot_ctrl = ChanCtrl->DstProtCtrl & 0x07;
859         unsigned dst_inc_bit = ChanCtrl->DstInc & 1;
860
861         unsigned src_burst_size =
862                 XDmaPs_ToBurstSizeBits(ChanCtrl->SrcBurstSize);
863         unsigned src_burst_len = (ChanCtrl->SrcBurstLen - 1) & 0x0F;
864         unsigned src_cache_ctrl = (ChanCtrl->SrcCacheCtrl & 0x03)
865                 | ((ChanCtrl->SrcCacheCtrl & 0x08) >> 1);
866         unsigned src_prot_ctrl = ChanCtrl->SrcProtCtrl & 0x07;
867         unsigned src_inc_bit = ChanCtrl->SrcInc & 1;
868
869         u32 ccr_value = (es << 28)
870                 | (dst_cache_ctrl << 25)
871                 | (dst_prot_ctrl << 22)
872                 | (dst_burst_len << 18)
873                 | (dst_burst_size << 15)
874                 | (dst_inc_bit << 14)
875                 | (src_cache_ctrl << 11)
876                 | (src_prot_ctrl << 8)
877                 | (src_burst_len << 4)
878                 | (src_burst_size << 1)
879                 | (src_inc_bit);
880
881         return ccr_value;
882 }
883
884 /****************************************************************************/
885 /**
886 * Construct a loop with only DMALD and DMAST as the body using loop counter 0.
887 * The function also makes sure the loop body and the lpend is in the same
888 * cache line.
889 *
890 * @param        DmaProgStart is the very start address of the DMA program.
891 *               This is used to calculate whether the loop is in a cache line.
892 * @param        CacheLength is the icache line length, in terms of bytes.
893 *               If it's zero, the performance enhancement feature will be
894 *               turned off.
895 * @param        DmaProgLoopStart The starting address of the loop (DMALP).
896 * @param        LoopCount The inner loop count. Loop count - 1 will be used to
897 *               initialize the loop counter.
898 *
899 * @return       The number of bytes the loop has.
900 *
901 * @note         None.
902 *
903 *****************************************************************************/
904 int XDmaPs_ConstructSingleLoop(char *DmaProgStart,
905                                 int CacheLength,
906                                 char *DmaProgLoopStart,
907                                 int LoopCount)
908 {
909         int CacheStartOffset;
910         int CacheEndOffset;
911         int NumNops;
912         char *DmaProgBuf = DmaProgLoopStart;
913
914         DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 0, LoopCount);
915
916         if (CacheLength > 0) {
917                 /*
918                  * the CacheLength > 0 switch is ued to turn on/off nop
919                  * insertion
920                  */
921                 CacheStartOffset = DmaProgBuf - DmaProgStart;
922                 CacheEndOffset = CacheStartOffset + 3;
923
924                 /*
925                  * check whether the body and lpend fit in one cache line
926                  */
927                 if (CacheStartOffset / CacheLength
928                     != CacheEndOffset / CacheLength) {
929                         /* insert the nops */
930                         NumNops = CacheLength
931                                 - CacheStartOffset % CacheLength;
932                         while (NumNops--) {
933                                 DmaProgBuf +=
934                                         XDmaPs_Instr_DMANOP(DmaProgBuf);
935                         }
936                 }
937         }
938
939         DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf);
940         DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf);
941         DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf,
942                                              DmaProgBuf - 2, 0);
943
944         return DmaProgBuf - DmaProgLoopStart;
945 }
946
947 /****************************************************************************/
948 /**
949 * Construct a nested loop with only DMALD and DMAST in the inner loop body.
950 * It uses loop counter 1 for the outer loop and loop counter 0 for the
951 * inner loop.
952 *
953 * @param        DmaProgStart is the very start address of the DMA program.
954 *               This is used to calculate whether the loop is in a cache line.
955 * @param        CacheLength is the icache line length, in terms of bytes.
956 *               If it's zero, the performance enhancement feature will be
957 *               turned off.
958 * @param        DmaProgLoopStart The starting address of the loop (DMALP).
959 * @param        LoopCountOuter The outer loop count. Loop count - 1 will be
960 *               used to initialize the loop counter.
961 * @param        LoopCountInner The inner loop count. Loop count - 1 will be
962 *               used to initialize the loop counter.
963 *
964 * @return       The number byes the nested loop program has.
965 *
966 * @note         None.
967 *
968 *****************************************************************************/
969 int XDmaPs_ConstructNestedLoop(char *DmaProgStart,
970                                 int CacheLength,
971                                 char *DmaProgLoopStart,
972                                 unsigned int LoopCountOuter,
973                                 unsigned int LoopCountInner)
974 {
975         int CacheStartOffset;
976         int CacheEndOffset;
977         int NumNops;
978         char *InnerLoopStart;
979         char *DmaProgBuf = DmaProgLoopStart;
980
981         DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 1, LoopCountOuter);
982         InnerLoopStart = DmaProgBuf;
983
984         if (CacheLength > 0) {
985                 /*
986                  * the CacheLength > 0 switch is ued to turn on/off nop
987                  * insertion
988                  */
989                 if (CacheLength < 8) {
990                         /*
991                          * if the cache line is too small to fit both loops
992                          * just align the inner loop
993                          */
994                         DmaProgBuf +=
995                                 XDmaPs_ConstructSingleLoop(DmaProgStart,
996                                                             CacheLength,
997                                                             DmaProgBuf,
998                                                             LoopCountInner);
999                         /* outer loop end */
1000                         DmaProgBuf +=
1001                                 XDmaPs_Instr_DMALPEND(DmaProgBuf,
1002                                                        InnerLoopStart,
1003                                                        1);
1004
1005                         /*
1006                          * the nested loop is constructed for
1007                          * smaller cache line
1008                          */
1009                         return DmaProgBuf - DmaProgLoopStart;
1010                 }
1011
1012                 /*
1013                  * Now let's handle the case where a cache line can
1014                  * fit the nested loops.
1015                  */
1016                 CacheStartOffset = DmaProgBuf - DmaProgStart;
1017                 CacheEndOffset = CacheStartOffset + 7;
1018
1019                 /*
1020                  * check whether the body and lpend fit in one cache line
1021                  */
1022                 if (CacheStartOffset / CacheLength
1023                     != CacheEndOffset / CacheLength) {
1024                         /* insert the nops */
1025                         NumNops = CacheLength
1026                                 - CacheStartOffset % CacheLength;
1027                         while (NumNops--) {
1028                                 DmaProgBuf +=
1029                                         XDmaPs_Instr_DMANOP(DmaProgBuf);
1030                         }
1031                 }
1032         }
1033
1034         /* insert the inner DMALP */
1035         DmaProgBuf += XDmaPs_Instr_DMALP(DmaProgBuf, 0, LoopCountInner);
1036
1037         /* DMALD and DMAST instructions */
1038         DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf);
1039         DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf);
1040
1041         /* inner DMALPEND */
1042         DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf,
1043                                              DmaProgBuf - 2, 0);
1044         /* outer DMALPEND */
1045         DmaProgBuf += XDmaPs_Instr_DMALPEND(DmaProgBuf,
1046                                              InnerLoopStart, 1);
1047
1048         /* return the number of bytes */
1049         return DmaProgBuf - DmaProgLoopStart;
1050 }
1051
1052 /*
1053  * [31:28] endian_swap_size     b0000
1054  * [27:25] dst_cache_ctrl       b000
1055  * [24:22] dst_prot_ctrl        b000
1056  * [21:18] dst_burst_len        b0000
1057  * [17:15] dst_burst_size       b000
1058  * [14]    dst_inc              b0
1059  * [27:25] src_cache_ctrl       b000
1060  * [24:22] src_prot_ctrl        b000
1061  * [21:18] src_burst_len        b0000
1062  * [17:15] src_burst_size       b000
1063  * [14]    src_inc              b0
1064  */
1065 #define XDMAPS_CCR_SINGLE_BYTE  (0x0)
1066 #define XDMAPS_CCR_M2M_SINGLE_BYTE      ((0x1 << 14) | 0x1)
1067
1068
1069 /****************************************************************************/
1070 /**
1071 *
1072 * Construct the DMA program based on the descriptions of the DMA transfer.
1073 * The function handles memory to memory DMA transfers.
1074 * It also handles unalgined head and small amount of residue tail.
1075 *
1076 * @param        Channel DMA channel number
1077 * @param        Cmd is the DMA command.
1078 * @param        CacheLength is the icache line length, in terms of bytes.
1079 *               If it's zero, the performance enhancement feature will be
1080 *               turned off.
1081 *
1082 * @returns      The number of bytes for the program.
1083 *
1084 * @note         None.
1085 *
1086 *****************************************************************************/
1087 static int XDmaPs_BuildDmaProg(unsigned Channel, XDmaPs_Cmd *Cmd,
1088                                 unsigned CacheLength)
1089 {
1090         /*
1091          * unpack arguments
1092          */
1093         char *DmaProgBuf = (char *)Cmd->GeneratedDmaProg;
1094         unsigned DevChan = Channel;
1095         unsigned long DmaLength = Cmd->BD.Length;
1096         u32 SrcAddr = Cmd->BD.SrcAddr;
1097
1098         unsigned SrcInc = Cmd->ChanCtrl.SrcInc;
1099         u32 DstAddr = Cmd->BD.DstAddr;
1100         unsigned DstInc = Cmd->ChanCtrl.DstInc;
1101
1102         char *DmaProgStart = DmaProgBuf;
1103
1104         unsigned int BurstBytes;
1105         unsigned int LoopCount;
1106         unsigned int LoopCount1 = 0;
1107         unsigned int LoopResidue = 0;
1108         unsigned int TailBytes;
1109         unsigned int TailWords;
1110         int DmaProgBytes;
1111         u32 CCRValue;
1112         unsigned int Unaligned;
1113         unsigned int UnalignedCount;
1114         unsigned int MemBurstSize = 1;
1115         u32 MemAddr = 0;
1116         unsigned int Index;
1117         unsigned int SrcUnaligned = 0;
1118         unsigned int DstUnaligned = 0;
1119
1120         XDmaPs_ChanCtrl *ChanCtrl;
1121         XDmaPs_ChanCtrl WordChanCtrl;
1122         static XDmaPs_ChanCtrl Mem2MemByteCC;
1123
1124         Mem2MemByteCC.EndianSwapSize = 0;
1125         Mem2MemByteCC.DstCacheCtrl = 0;
1126         Mem2MemByteCC.DstProtCtrl = 0;
1127         Mem2MemByteCC.DstBurstLen = 1;
1128         Mem2MemByteCC.DstBurstSize = 1;
1129         Mem2MemByteCC.DstInc = 1;
1130         Mem2MemByteCC.SrcCacheCtrl = 0;
1131         Mem2MemByteCC.SrcProtCtrl = 0;
1132         Mem2MemByteCC.SrcBurstLen = 1;
1133         Mem2MemByteCC.SrcBurstSize = 1;
1134         Mem2MemByteCC.SrcInc = 1;
1135
1136         ChanCtrl = &Cmd->ChanCtrl;
1137
1138         /* insert DMAMOV for SAR and DAR */
1139         DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf,
1140                                            XDMAPS_MOV_SAR,
1141                                            SrcAddr);
1142         DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf,
1143                                          XDMAPS_MOV_DAR,
1144                                          DstAddr);
1145
1146
1147         if (ChanCtrl->SrcInc)
1148                 SrcUnaligned = SrcAddr % ChanCtrl->SrcBurstSize;
1149
1150         if (ChanCtrl->DstInc)
1151                 DstUnaligned = DstAddr % ChanCtrl->DstBurstSize;
1152
1153         if ((SrcUnaligned && DstInc) || (DstUnaligned && SrcInc)) {
1154                 ChanCtrl = &Mem2MemByteCC;
1155         }
1156
1157         if (ChanCtrl->SrcInc) {
1158                 MemBurstSize = ChanCtrl->SrcBurstSize;
1159                 MemAddr = SrcAddr;
1160
1161         } else if (ChanCtrl->DstInc) {
1162                 MemBurstSize = ChanCtrl->DstBurstSize;
1163                 MemAddr = DstAddr;
1164         }
1165
1166         /* check whether the head is aligned or not */
1167         Unaligned = MemAddr % MemBurstSize;
1168
1169         if (Unaligned) {
1170                 /* if head is unaligned, transfer head in bytes */
1171                 UnalignedCount = MemBurstSize - Unaligned;
1172                 CCRValue = XDMAPS_CCR_SINGLE_BYTE
1173                         | (SrcInc & 1)
1174                         | ((DstInc & 1) << 14);
1175
1176                 DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf,
1177                                                    XDMAPS_MOV_CCR,
1178                                                    CCRValue);
1179
1180                 for (Index = 0; Index < UnalignedCount; Index++) {
1181                         DmaProgBuf += XDmaPs_Instr_DMALD(DmaProgBuf);
1182                         DmaProgBuf += XDmaPs_Instr_DMAST(DmaProgBuf);
1183                 }
1184
1185                 DmaLength -= UnalignedCount;
1186         }
1187
1188         /* now the burst transfer part */
1189         CCRValue = XDmaPs_ToCCRValue(ChanCtrl);
1190         DmaProgBuf += XDmaPs_Instr_DMAMOV(DmaProgBuf,
1191                                            XDMAPS_MOV_CCR,
1192                                            CCRValue);
1193
1194         BurstBytes = ChanCtrl->SrcBurstSize * ChanCtrl->SrcBurstLen;
1195
1196         LoopCount = DmaLength / BurstBytes;
1197         TailBytes = DmaLength % BurstBytes;
1198
1199         /*
1200          * the loop count register is 8-bit wide, so if we need
1201          * a larger loop, we need to have nested loops
1202          */
1203         if (LoopCount > 256) {
1204                 LoopCount1 = LoopCount / 256;
1205                 if (LoopCount1 > 256) {
1206                         xil_printf("DMA operation cannot fit in a 2-level "
1207                                    "loop for channel %d, please reduce the "
1208                                    "DMA length or increase the burst size or "
1209                                    "length",
1210                                    Channel);
1211                         return 0;
1212                 }
1213                 LoopResidue = LoopCount % 256;
1214
1215                 if (LoopCount1 > 1)
1216                         DmaProgBuf +=
1217                                 XDmaPs_ConstructNestedLoop(DmaProgStart,
1218                                                             CacheLength,
1219                                                             DmaProgBuf,
1220                                                             LoopCount1,
1221                                                             256);
1222                 else
1223                         DmaProgBuf +=
1224                                 XDmaPs_ConstructSingleLoop(DmaProgStart,
1225                                                             CacheLength,
1226                                                             DmaProgBuf,
1227                                                             256);
1228
1229                 /* there will be some that cannot be covered by
1230                  * nested loops
1231                  */
1232                 LoopCount = LoopResidue;
1233         }
1234
1235         if (LoopCount > 0) {
1236                 DmaProgBuf += XDmaPs_ConstructSingleLoop(DmaProgStart,
1237                                                             CacheLength,
1238                                                             DmaProgBuf,
1239                                                             LoopCount);
1240         }
1241
1242         if (TailBytes) {
1243                 /* handle the tail */
1244                 TailWords = TailBytes / MemBurstSize;
1245                 TailBytes = TailBytes % MemBurstSize;
1246
1247                 if (TailWords) {
1248                         WordChanCtrl = *ChanCtrl;
1249                         /*
1250                          * if we can transfer the tail in words, we will
1251                          * transfer words as much as possible
1252                          */
1253                         WordChanCtrl.SrcBurstSize = MemBurstSize;
1254                         WordChanCtrl.SrcBurstLen = 1;
1255                         WordChanCtrl.DstBurstSize = MemBurstSize;
1256                         WordChanCtrl.DstBurstLen = 1;
1257
1258
1259                         /*
1260                          * the burst length is 1
1261                          */
1262                         CCRValue = XDmaPs_ToCCRValue(&WordChanCtrl);
1263
1264                         DmaProgBuf +=
1265                                 XDmaPs_Instr_DMAMOV(DmaProgBuf,
1266                                                    XDMAPS_MOV_CCR,
1267                                                    CCRValue);
1268                         DmaProgBuf +=
1269                                 XDmaPs_ConstructSingleLoop(DmaProgStart,
1270                                                             CacheLength,
1271                                                             DmaProgBuf,
1272                                                             TailWords);
1273
1274                 }
1275
1276                 if (TailBytes) {
1277                         /*
1278                          * for the rest, we'll tranfer in bytes
1279                          */
1280                         /*
1281                          * So far just to be safe, the tail bytes
1282                          * are transfered in a loop. We can optimize a little
1283                          * to perform a burst.
1284                          */
1285                         CCRValue = XDMAPS_CCR_SINGLE_BYTE
1286                                 | (SrcInc & 1)
1287                                 | ((DstInc & 1) << 14);
1288
1289                         DmaProgBuf +=
1290                                 XDmaPs_Instr_DMAMOV(DmaProgBuf,
1291                                                    XDMAPS_MOV_CCR,
1292                                                    CCRValue);
1293
1294                         DmaProgBuf +=
1295                                 XDmaPs_ConstructSingleLoop(DmaProgStart,
1296                                                             CacheLength,
1297                                                             DmaProgBuf,
1298                                                             TailBytes);
1299
1300                 }
1301         }
1302
1303         DmaProgBuf += XDmaPs_Instr_DMASEV(DmaProgBuf, DevChan);
1304         DmaProgBuf += XDmaPs_Instr_DMAEND(DmaProgBuf);
1305
1306         DmaProgBytes = DmaProgBuf - DmaProgStart;
1307
1308         Xil_DCacheFlushRange((u32)DmaProgStart, DmaProgBytes);
1309
1310         return DmaProgBytes;
1311
1312 }
1313
1314
1315 /****************************************************************************/
1316 /**
1317 *
1318 * Generate a DMA program based for the DMA command, the buffer will be pointed
1319 * by the GeneratedDmaProg field of the command.
1320 *
1321 * @param        InstPtr is then DMA instance.
1322 * @param        Channel is the DMA channel number.
1323 * @param        Cmd is the DMA command.
1324 *
1325 * @return       - XST_SUCCESS on success.
1326 *               - XST_FAILURE if it fails
1327 *
1328 * @note         None.
1329 *
1330 *****************************************************************************/
1331 int XDmaPs_GenDmaProg(XDmaPs *InstPtr, unsigned int Channel, XDmaPs_Cmd *Cmd)
1332 {
1333         void *Buf;
1334         int ProgLen;
1335         XDmaPs_ChannelData *ChanData;
1336         XDmaPs_ChanCtrl *ChanCtrl;
1337
1338         Xil_AssertNonvoid(InstPtr != NULL);
1339         Xil_AssertNonvoid(Cmd != NULL);
1340
1341
1342         if (Channel > XDMAPS_CHANNELS_PER_DEV)
1343                 return XST_FAILURE;
1344
1345         ChanData = InstPtr->Chans + Channel;
1346         ChanCtrl = &Cmd->ChanCtrl;
1347
1348         if (ChanCtrl->SrcBurstSize * ChanCtrl->SrcBurstLen
1349             != ChanCtrl->DstBurstSize * ChanCtrl->DstBurstLen) {
1350                 xil_printf("source burst_size * burst_len does not match "
1351                            "that of destination\r\n");
1352                 return XST_FAILURE;
1353         }
1354
1355
1356         /*
1357          * unaligned fixed address is not supported
1358          */
1359         if (!ChanCtrl->SrcInc && Cmd->BD.SrcAddr % ChanCtrl->SrcBurstSize) {
1360                 xil_printf("source address is fixed but is unaligned\r\n");
1361                 return XST_FAILURE;
1362         }
1363
1364         if (!ChanCtrl->DstInc && Cmd->BD.DstAddr % ChanCtrl->DstBurstSize) {
1365                 xil_printf("destination address is fixed but is "
1366                            "unaligned\r\n");
1367                 return XST_FAILURE;
1368         }
1369
1370         Buf = XDmaPs_BufPool_Allocate(ChanData->ProgBufPool);
1371         if (Buf == NULL) {
1372                 xil_printf("failed to allocate program buffer\r\n");
1373                 return XST_FAILURE;
1374         }
1375
1376         Cmd->GeneratedDmaProg = Buf;
1377         ProgLen = XDmaPs_BuildDmaProg(Channel, Cmd,
1378                                        InstPtr->CacheLength);
1379         Cmd->GeneratedDmaProgLength = ProgLen;
1380
1381
1382 #ifdef XDMAPS_DEBUG
1383         XDmaPs_Print_DmaProg(Cmd);
1384 #endif
1385
1386         if (ProgLen <= 0) {
1387                 /* something wrong, release the buffer */
1388                 XDmaPs_BufPool_Free(ChanData->ProgBufPool, Buf);
1389                 Cmd->GeneratedDmaProgLength = 0;
1390                 Cmd->GeneratedDmaProg = NULL;
1391                 return XST_FAILURE;
1392         }
1393
1394         return XST_SUCCESS;
1395 }
1396
1397
1398 /****************************************************************************/
1399 /**
1400  * Free the DMA program buffer that is pointed by the GeneratedDmaProg field
1401  * of the command.
1402  *
1403  * @param       InstPtr is then DMA instance.
1404  * @param       Channel is the DMA channel number.
1405  * @param       Cmd is the DMA command.
1406  *
1407  * @return      XST_SUCCESS on success.
1408  *              XST_FAILURE if there is any error.
1409  *
1410  * @note        None.
1411  *
1412  ****************************************************************************/
1413 int XDmaPs_FreeDmaProg(XDmaPs *InstPtr, unsigned int Channel, XDmaPs_Cmd *Cmd)
1414 {
1415
1416         void *Buf;
1417         XDmaPs_ChannelData *ChanData;
1418
1419         Xil_AssertNonvoid(InstPtr != NULL);
1420         Xil_AssertNonvoid(Cmd != NULL);
1421
1422         if (Channel > XDMAPS_CHANNELS_PER_DEV)
1423                 return XST_FAILURE;
1424
1425         Buf = (void *)Cmd->GeneratedDmaProg;
1426         ChanData = InstPtr->Chans + Channel;
1427
1428         if (Buf) {
1429                 XDmaPs_BufPool_Free(ChanData->ProgBufPool, Buf);
1430                 Cmd->GeneratedDmaProg = 0;
1431                 Cmd->GeneratedDmaProgLength = 0;
1432         }
1433
1434         return XST_SUCCESS;
1435 }
1436
1437
1438 /****************************************************************************/
1439 /**
1440 *
1441 * Start a DMA command. The command can only be invoked when the channel
1442 * is idle. The driver takes the command, generates DMA program if needed,
1443 * then pass the program to DMAC to execute.
1444 *
1445 * @param        InstPtr is then DMA instance.
1446 * @param        Channel is the DMA channel number.
1447 * @param        Cmd is the DMA command.
1448 * @param        HoldDmaProg is tag indicating whether the driver can release
1449 *               the allocated DMA buffer or not. If a user wants to examine the
1450 *               generated DMA program, the flag should be set to 1. After the
1451 *               DMA program is finished, a user needs to explicity free the
1452 *               buffer.
1453 *
1454 * @return
1455 *               - XST_SUCCESS on success
1456 *               - XST_DEVICE_BUSY if DMA is busy
1457 *               - XST_FAILURE on other failures
1458 *
1459 * @note         None.
1460 *
1461 ****************************************************************************/
1462 int XDmaPs_Start(XDmaPs *InstPtr, unsigned int Channel,
1463                   XDmaPs_Cmd *Cmd,
1464                   int HoldDmaProg)
1465 {
1466         int Status;
1467         u32 DmaProg = 0;
1468         u32 Inten;
1469
1470         Xil_AssertNonvoid(InstPtr != NULL);
1471         Xil_AssertNonvoid(Cmd != NULL);
1472
1473
1474         Cmd->DmaStatus = XST_FAILURE;
1475
1476         if (XDmaPs_IsActive(InstPtr, Channel))
1477                 return XST_DEVICE_BUSY;
1478
1479         if (!Cmd->UserDmaProg && !Cmd->GeneratedDmaProg) {
1480                 Status = XDmaPs_GenDmaProg(InstPtr, Channel, Cmd);
1481                 if (Status)
1482                         return XST_FAILURE;
1483         }
1484
1485         InstPtr->Chans[Channel].HoldDmaProg = HoldDmaProg;
1486
1487         if (Cmd->UserDmaProg)
1488                 DmaProg = (u32)Cmd->UserDmaProg;
1489         else if (Cmd->GeneratedDmaProg)
1490                 DmaProg = (u32)Cmd->GeneratedDmaProg;
1491
1492         if (DmaProg) {
1493                 /* enable the interrupt */
1494                 Inten = XDmaPs_ReadReg(InstPtr->Config.BaseAddress,
1495                                         XDMAPS_INTEN_OFFSET);
1496                 Inten |= 0x01 << Channel; /* set the correpsonding bit */
1497                 XDmaPs_WriteReg(InstPtr->Config.BaseAddress,
1498                                  XDMAPS_INTEN_OFFSET,
1499                                  Inten);
1500                 Inten = XDmaPs_ReadReg(InstPtr->Config.BaseAddress,
1501                                 XDMAPS_INTEN_OFFSET);
1502
1503                 InstPtr->Chans[Channel].DmaCmdToHw = Cmd;
1504
1505                 if (Cmd->ChanCtrl.SrcInc) {
1506                         Xil_DCacheFlushRange(Cmd->BD.SrcAddr, Cmd->BD.Length);
1507                 }
1508                 if (Cmd->ChanCtrl.DstInc) {
1509                         Xil_DCacheInvalidateRange(Cmd->BD.DstAddr,
1510                                         Cmd->BD.Length);
1511                 }
1512
1513                 Status = XDmaPs_Exec_DMAGO(InstPtr->Config.BaseAddress,
1514                                             Channel, DmaProg);
1515         }
1516         else {
1517                 InstPtr->Chans[Channel].DmaCmdToHw = NULL;
1518                 Status = XST_FAILURE;
1519         }
1520
1521         return Status;
1522 }
1523
1524 /****************************************************************************/
1525 /**
1526 *
1527 * Checks  whether the DMA channel is active or idle.
1528 *
1529 * @param        InstPtr is the DMA instance.
1530 * @param        Channel is the DMA channel number.
1531 *
1532 * @return       0: if the channel is idle
1533 *               1: otherwise
1534 *
1535 * @note         None.
1536 *
1537 *****************************************************************************/
1538 int XDmaPs_IsActive(XDmaPs *InstPtr, unsigned int Channel)
1539 {
1540         Xil_AssertNonvoid(InstPtr != NULL);
1541
1542         /* Need to assert Channel is in range */
1543         if (Channel > XDMAPS_CHANNELS_PER_DEV)
1544                 return  0;
1545
1546         return InstPtr->Chans[Channel].DmaCmdToHw != NULL;
1547 }
1548
1549
1550
1551 /****************************************************************************/
1552 /**
1553 *
1554 * Allocate a buffer of the DMA program buffer from the pool.
1555 *
1556 * @param        Pool the DMA program pool.
1557 *
1558 * @return       The allocated buffer, NULL if there is any error.
1559 *
1560 * @note         None.
1561 *
1562 *****************************************************************************/
1563 static void *XDmaPs_BufPool_Allocate(XDmaPs_ProgBuf *Pool)
1564 {
1565         int Index;
1566
1567         Xil_AssertNonvoid(Pool != NULL);
1568
1569         for (Index = 0; Index < XDMAPS_MAX_CHAN_BUFS; Index++) {
1570                 if (!Pool[Index].Allocated) {
1571                         Pool[Index].Allocated = 1;
1572                         return Pool[Index].Buf;
1573                 }
1574         }
1575
1576         return NULL;
1577
1578 }
1579
1580 /*****************************************************************************/
1581 /**
1582 *
1583 * Driver done interrupt service routine for channel 0. We need this done ISR
1584 * mainly because the driver needs to release the DMA program buffer.
1585 * This is the one that connects the GIC
1586 *
1587 * @param        InstPtr is the DMA instance.
1588 *
1589 * @return       None.
1590 *
1591 * @note         None.
1592 *
1593 ******************************************************************************/
1594 void XDmaPs_DoneISR_0(XDmaPs *InstPtr)
1595 {
1596         XDmaPs_DoneISR_n(InstPtr, 0);
1597 }
1598
1599 /*****************************************************************************/
1600 /**
1601 *
1602 * Driver done interrupt service routine for channel 1. We need this done ISR
1603 * mainly because the driver needs to release the DMA program buffer.
1604 * This is the one that connects the GIC
1605 *
1606 * @param        InstPtr is the DMA instance.
1607 *
1608 * @return       None.
1609 *
1610 * @note         None.
1611 *
1612 ******************************************************************************/
1613 void XDmaPs_DoneISR_1(XDmaPs *InstPtr)
1614 {
1615         XDmaPs_DoneISR_n(InstPtr, 1);
1616 }
1617
1618 /*****************************************************************************/
1619 /**
1620 *
1621 * Driver done interrupt service routine for channel 2. We need this done ISR
1622 * mainly because the driver needs to release the DMA program buffer.
1623 * This is the one that connects the GIC
1624 *
1625 * @param        InstPtr is the DMA instance.
1626 *
1627 * @return       None.
1628 *
1629 * @note         None.
1630 *
1631 ******************************************************************************/
1632 void XDmaPs_DoneISR_2(XDmaPs *InstPtr)
1633 {
1634         XDmaPs_DoneISR_n(InstPtr, 2);
1635 }
1636
1637 /*****************************************************************************/
1638 /**
1639 *
1640 * Driver done interrupt service routine for channel 3. We need this done ISR
1641 * mainly because the driver needs to release the DMA program buffer.
1642 * This is the one that connects the GIC
1643 *
1644 * @param        InstPtr is the DMA instance.
1645 *
1646 * @return       None.
1647 *
1648 * @note         None.
1649 *
1650 ******************************************************************************/
1651 void XDmaPs_DoneISR_3(XDmaPs *InstPtr)
1652 {
1653         XDmaPs_DoneISR_n(InstPtr, 3);
1654 }
1655
1656 /*****************************************************************************/
1657 /**
1658 *
1659 * Driver done interrupt service routine for channel 4. We need this done ISR
1660 * mainly because the driver needs to release the DMA program buffer.
1661 * This is the one that connects the GIC
1662 *
1663 * @param        InstPtr is the DMA instance.
1664 *
1665 * @return       None.
1666 *
1667 * @note         None.
1668 *
1669 ******************************************************************************/
1670 void XDmaPs_DoneISR_4(XDmaPs *InstPtr)
1671 {
1672         XDmaPs_DoneISR_n(InstPtr, 4);
1673 }
1674
1675 /*****************************************************************************/
1676 /**
1677 *
1678 * Driver done interrupt service routine for channel 5. We need this done ISR
1679 * mainly because the driver needs to release the DMA program buffer.
1680 * This is the one that connects the GIC
1681 *
1682 * @param        InstPtr is the DMA instance.
1683 *
1684 * @return       None.
1685 *
1686 * @note         None.
1687 *
1688 ******************************************************************************/
1689 void XDmaPs_DoneISR_5(XDmaPs *InstPtr)
1690 {
1691         XDmaPs_DoneISR_n(InstPtr, 5);
1692 }
1693
1694 /*****************************************************************************/
1695 /**
1696 *
1697 * Driver done interrupt service routine for channel 6. We need this done ISR
1698 * mainly because the driver needs to release the DMA program buffer.
1699 * This is the one that connects the GIC
1700 *
1701 * @param        InstPtr is the DMA instance.
1702 *
1703 * @return       None.
1704 *
1705 * @note         None.
1706 *
1707 ******************************************************************************/
1708 void XDmaPs_DoneISR_6(XDmaPs *InstPtr)
1709 {
1710         XDmaPs_DoneISR_n(InstPtr, 6);
1711 }
1712
1713 /*****************************************************************************/
1714 /**
1715 *
1716 * Driver done interrupt service routine for channel 7. We need this done ISR
1717 * mainly because the driver needs to release the DMA program buffer.
1718 * This is the one that connects the GIC
1719 *
1720 * @param        InstPtr is the DMA instance.
1721 *
1722 * @return       None.
1723 *
1724 * @note         None.
1725 *
1726 ******************************************************************************/
1727 void XDmaPs_DoneISR_7(XDmaPs *InstPtr)
1728 {
1729         XDmaPs_DoneISR_n(InstPtr, 7);
1730 }
1731
1732 #ifndef XDMAPS_MAX_WAIT
1733 #define XDMAPS_MAX_WAIT 4000
1734 #endif
1735
1736 /****************************************************************************/
1737 /**
1738 * Use the debug registers to kill the DMA thread.
1739 *
1740 * @param        BaseAddr is DMA device base address.
1741 * @param        Channel is the DMA channel number.
1742 * @param        Thread is Debug thread encoding.
1743 *               0: DMA manager thread, 1: DMA channel.
1744 *
1745 * @return       0 on success, -1 on time out
1746 *
1747 * @note         None.
1748 *
1749 *****************************************************************************/
1750 static int XDmaPs_Exec_DMAKILL(u32 BaseAddr,
1751                                 unsigned int Channel,
1752                                 unsigned int Thread)
1753 {
1754         u32 DbgInst0;
1755         int WaitCount;
1756
1757         DbgInst0 = XDmaPs_DBGINST0(0, 0x01, Channel, Thread);
1758
1759         /* wait while debug status is busy */
1760         WaitCount = 0;
1761         while ((XDmaPs_ReadReg(BaseAddr, XDMAPS_DBGSTATUS_OFFSET)
1762                & XDMAPS_DBGSTATUS_BUSY)
1763                && (WaitCount < XDMAPS_MAX_WAIT))
1764                 WaitCount++;
1765
1766         if (WaitCount >= XDMAPS_MAX_WAIT) {
1767                 /* wait time out */
1768                 xil_printf("PL330 device at %x debug status busy time out\n",
1769                        BaseAddr);
1770
1771                 return -1;
1772         }
1773
1774         /* write debug instruction 0 */
1775         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST0_OFFSET, DbgInst0);
1776
1777         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST1_OFFSET, 0);
1778
1779
1780         /* run the command in DbgInst0 and DbgInst1 */
1781         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGCMD_OFFSET, 0);
1782
1783         return 0;
1784 }
1785
1786 /****************************************************************************/
1787 /**
1788 *
1789 *
1790 * Free a buffer of the DMA program buffer.
1791 * @param        Pool the DMA program pool.
1792 * @param        Buf the DMA program buffer to be release.
1793 *
1794 * @return       None
1795 *
1796 * @note         None.
1797 *
1798 *****************************************************************************/
1799 static void XDmaPs_BufPool_Free(XDmaPs_ProgBuf *Pool, void *Buf)
1800 {
1801         int Index;
1802         Xil_AssertVoid(Pool != NULL);
1803
1804         for (Index = 0; Index < XDMAPS_MAX_CHAN_BUFS; Index++) {
1805                 if (Pool[Index].Buf == Buf) {
1806                         if (Pool[Index].Allocated) {
1807                                 Pool[Index].Allocated = 0;
1808                         }
1809                 }
1810         }
1811 }
1812
1813 /*****************************************************************************/
1814 /**
1815 * XDmaPs_Exec_DMAGO - Execute the DMAGO to start a channel.
1816 *
1817 * @param        BaseAddr PL330 device base address
1818 * @param        Channel Channel number for the device
1819 * @param        DmaProg DMA program starting address, this should be DMA address
1820 *
1821 * @return       0 on success, -1 on time out
1822 *
1823 * @note         None.
1824 *
1825 ****************************************************************************/
1826 static int XDmaPs_Exec_DMAGO(u32 BaseAddr, unsigned int Channel, u32 DmaProg)
1827 {
1828         char DmaGoProg[8];
1829         u32 DbgInst0;
1830         u32 DbgInst1;
1831
1832         int WaitCount;
1833
1834         XDmaPs_Instr_DMAGO(DmaGoProg, Channel, DmaProg, 0);
1835
1836         DbgInst0 = XDmaPs_DBGINST0(*(DmaGoProg + 1), *DmaGoProg, 0, 0);
1837         DbgInst1 = (u32)DmaProg;
1838
1839         /* wait while debug status is busy */
1840         WaitCount = 0;
1841         while ((XDmaPs_ReadReg(BaseAddr, XDMAPS_DBGSTATUS_OFFSET)
1842                & XDMAPS_DBGSTATUS_BUSY)
1843                && (WaitCount < XDMAPS_MAX_WAIT)) {
1844
1845                 WaitCount++;
1846         }
1847
1848         if (WaitCount >= XDMAPS_MAX_WAIT) {
1849                 xil_printf("PL330 device at %x debug status busy time out\r\n",
1850                            BaseAddr);
1851                 return -1;
1852         }
1853
1854         /* write debug instruction 0 */
1855         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST0_OFFSET, DbgInst0);
1856         /* write debug instruction 1 */
1857         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGINST1_OFFSET, DbgInst1);
1858
1859
1860         /* wait while the DMA Manager is busy */
1861         WaitCount = 0;
1862         while ((XDmaPs_ReadReg(BaseAddr,
1863                                 XDMAPS_DS_OFFSET) & XDMAPS_DS_DMA_STATUS)
1864                != XDMAPS_DS_DMA_STATUS_STOPPED
1865                && WaitCount <= XDMAPS_MAX_WAIT) {
1866                 WaitCount++;
1867         }
1868
1869         if (WaitCount >= XDMAPS_MAX_WAIT) {
1870                 xil_printf("PL330 device at %x debug status busy time out\r\n",
1871                            BaseAddr);
1872                 return -1;
1873         }
1874
1875         /* run the command in DbgInst0 and DbgInst1 */
1876         XDmaPs_WriteReg(BaseAddr, XDMAPS_DBGCMD_OFFSET, 0);
1877
1878         return 0;
1879 }
1880
1881
1882 /****************************************************************************/
1883 /**
1884 *
1885 * It's the generic Done ISR.
1886 * @param        InstPtr is the DMA instance.
1887 * @param        Channel is the DMA channel numer.
1888 *
1889 * @return       None.*
1890 *
1891 * @note         None.
1892 *
1893 *****************************************************************************/
1894 static void XDmaPs_DoneISR_n(XDmaPs *InstPtr, unsigned Channel)
1895 {
1896
1897         void *DmaProgBuf;
1898         XDmaPs_ChannelData *ChanData;
1899         XDmaPs_Cmd *DmaCmd;
1900         //u32 Value;
1901
1902         ChanData = InstPtr->Chans + Channel;
1903
1904         /*Value = XDmaPs_ReadReg(InstPtr->Config.BaseAddress,
1905                         XDMAPS_INTSTATUS_OFFSET);*/
1906
1907         /* clear the interrupt status */
1908         XDmaPs_WriteReg(InstPtr->Config.BaseAddress,
1909                         XDMAPS_INTCLR_OFFSET,
1910                         1 << ChanData->ChanId);
1911
1912         /*Value = XDmaPs_ReadReg(InstPtr->Config.BaseAddress,
1913                         XDMAPS_INTSTATUS_OFFSET);*/
1914
1915
1916         if ((DmaCmd = ChanData->DmaCmdToHw)) {
1917                 if (!ChanData->HoldDmaProg) {
1918                         DmaProgBuf = (void *)DmaCmd->GeneratedDmaProg;
1919                         if (DmaProgBuf)
1920                                 XDmaPs_BufPool_Free(ChanData->ProgBufPool,
1921                                                      DmaProgBuf);
1922                         DmaCmd->GeneratedDmaProg = NULL;
1923                 }
1924
1925                 DmaCmd->DmaStatus = 0;
1926                 ChanData->DmaCmdToHw = NULL;
1927                 ChanData->DmaCmdFromHw = DmaCmd;
1928
1929                 if (ChanData->DoneHandler)
1930                         ChanData->DoneHandler(Channel, DmaCmd,
1931                                               ChanData->DoneRef);
1932         }
1933
1934 }
1935
1936
1937 /****************************************************************************/
1938 /**
1939 * Prints the content of the buffer in bytes
1940 * @param        Buf is the buffer.
1941 * @param        Length is the length of the DMA program.
1942 *
1943 * @return       None.
1944 *
1945 * @note         None.
1946 ****************************************************************************/
1947 static void XDmaPs_Print_DmaProgBuf(char *Buf, int Length)
1948 {
1949         int Index;
1950         for (Index = 0; Index < Length; Index++)
1951                 xil_printf("[%x] %x\r\n", Index, Buf[Index]);
1952
1953 }
1954 /****************************************************************************/
1955 /**
1956 * Print the Dma Prog Contents.
1957 *
1958 * @param        Cmd is the command buffer.
1959 *
1960 * @return       None.
1961 *
1962 * @note         None.
1963 *
1964 *****************************************************************************/
1965  void XDmaPs_Print_DmaProg(XDmaPs_Cmd *Cmd)
1966 {
1967         if (Cmd->GeneratedDmaProg && Cmd->GeneratedDmaProgLength) {
1968                 xil_printf("Generated DMA program (%d):\r\n",
1969                            Cmd->GeneratedDmaProgLength);
1970                 XDmaPs_Print_DmaProgBuf((char *)Cmd->GeneratedDmaProg,
1971                                          Cmd->GeneratedDmaProgLength);
1972         }
1973
1974         if (Cmd->UserDmaProg && Cmd->UserDmaProgLength) {
1975                 xil_printf("User defined DMA program (%d):\r\n",
1976                            Cmd->UserDmaProgLength);
1977                 XDmaPs_Print_DmaProgBuf((char *)Cmd->UserDmaProg,
1978                                          Cmd->UserDmaProgLength);
1979         }
1980 }
1981
1982
1983 /** @} */