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