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