1 /*
2 * csl2_dat.c
3 *
4 * Implements the CSL DAT2 API using EDMA3 Driver and Resource Manager Package
5 * (EDMA3LLD). Behaviour mimics DAT2 on EDMA2 hardware.
6 *
7 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
8 *
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the
20 * distribution.
21 *
22 * Neither the name of Texas Instruments Incorporated nor the names of
23 * its contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 */
40 #include <stdio.h>
41 #include <csl_dat.h>
43 /*
44 * Includes for accessing EDMA3 DRV and RM layer
45 */
46 #include <ti/sdo/edma3/drv/edma3_drv.h>
49 /*
50 * Include for setting up the EDMA3 LLD
51 */
52 #include <csl2_dat_edma3lld.h>
55 /*
56 * extern declarations
57 */
59 /*
60 * OS dependent functions, that must be implemented by user of CSL DAT adapter
61 * These functions mark the entry and exit to critical sections of the code
62 */
63 extern void _dat_critical_section_enter();
64 extern void _dat_critical_section_exit();
66 /*
67 * Flag to indicate if EDMA3 LLD was initialized before calling the DAT APIs
68 */
69 extern int DAT_EDMA3LLD_initCalled;
71 /*
72 * typedef declarations
73 */
75 typedef struct DAT_EDMA3LLD_ChannelDesc {
77 /* Holds the param number allocated */
78 Uint32 paramNo;
80 /* Holds the tcc number allocated */
81 Uint32 tccNo;
83 } DAT_EDMA3LLD_ChannelDesc;
85 /*
86 * static variable definitions
87 */
89 /*
90 * Max size array to hold the allocated resources for DAT
91 */
92 static DAT_EDMA3LLD_ChannelDesc
93 DAT_allocatedChannels[DAT_EDMA3LLD_HW_MAXPHYCHANNELS];
94 /*
95 * Flag to indicate that the DAT instance has been opened
96 */
97 static Uint32 DAT_EDMA3LLD_openFlag = 0;
99 /*
100 * 64 bit internal Transfer completion register, used to hold status
101 * of the channel
102 * It has a bit set to one whenever a Transfer is submitted, and cleared
103 * when it completes
104 */
105 static volatile Uint32 TransferCompleteH = 0x0;
106 static volatile Uint32 TransferCompleteL = 0x0;
108 /*
109 * Set to the last allocated bit index number in the TransferComplete fxn
110 */
111 static Uint32 lastAllocatedIndex = DAT_INVALID_ID;
113 /*
114 * static function declarations
115 */
116 /*
117 * Obtain the next free channel from available channels
118 */
119 static inline Uint32 _getFreeChannel(Uint32 *tccNum);
121 /*
122 * global variable definitions
123 */
125 /*
126 * Holds the EDMA3 driver handle
127 */
128 EDMA3_DRV_Handle DAT_EDMA3LLD_hEdma = NULL;
130 /*
131 * number of EDMA3 channels allocated for the DAT module
132 */
133 int DAT_EDMA3LLD_numAllocatedChannels = 0;
136 /*
137 * global function definitions
138 */
141 /*
142 * ======== DAT_open =========
143 * Opens the DAT module, called before all other DAT APIs
144 * Ignore all paramters of DAT_open, open any channel,
145 * all channels are opened with equal priority
146 * All channels can be used in 2D mode etc, flags are not applicable
147 */
148 int DAT_open(int chNum, int priority, Uint32 flags) {
150 int i = 0;
151 int j = 0;
152 Uint32 chaNum = DAT_INVALID_ID;
153 Uint32 tccNum = DAT_INVALID_ID;
155 chNum = chNum;
156 priority = priority;
157 flags = flags;
159 /*
160 * Ensure _initCalled is called before DAT_open
161 * Also ensure DAT_open is called only once
162 */
163 _dat_critical_section_enter();
165 if (DAT_EDMA3LLD_initCalled == 0) {
166 _dat_critical_section_exit();
167 return 0;
168 }
170 if (1 == DAT_EDMA3LLD_openFlag) {
171 _dat_critical_section_exit();
172 return 0;
173 }
174 DAT_EDMA3LLD_openFlag = 1;
175 _dat_critical_section_exit();
177 /*
178 * Request default number of channels and Tccs from the EDMA3 DRV package
179 */
180 for(i=0; i < DAT_EDMA3LLD_numAllocatedChannels; i++) {
181 chaNum = EDMA3_DRV_QDMA_CHANNEL_ANY;
182 tccNum = EDMA3_DRV_TCC_ANY;
184 /*
185 * EDMA3 DRV call to request for channel and tcc resources
186 */
187 if (EDMA3_DRV_SOK != EDMA3_DRV_requestChannel(DAT_EDMA3LLD_hEdma,
188 &chaNum, &tccNum,
189 (EDMA3_RM_EventQueue)DAT_EDMA3LLD_HW_EVT_QUEUE_ID,
190 NULL /*(EDMA3_RM_TccCallback)&_transferComplete*/, NULL)) {
192 /*
193 * Error requesting channels, Clean up all channels requested so far
194 */
195 for(j = i-1; j >=0; j--) {
196 EDMA3_DRV_freeChannel(DAT_EDMA3LLD_hEdma,
197 DAT_allocatedChannels[j].paramNo);
198 DAT_allocatedChannels[i].paramNo = DAT_INVALID_ID;
199 DAT_allocatedChannels[i].tccNo = DAT_INVALID_ID;
200 }
202 if (EDMA3_DRV_SOK != EDMA3_DRV_close(DAT_EDMA3LLD_hEdma, NULL)){
203 printf("Error closing DRV instance \n");
204 }
205 else {
206 if (EDMA3_DRV_SOK != EDMA3_DRV_delete(DAT_EDMA3LLD_HW_INST_ID,
207 NULL)){
208 printf("Error deleting EDMA3 DRV\n");
209 }
210 }
212 DAT_EDMA3LLD_openFlag = 0;
213 return 0;
214 }
216 /*
217 * Store the allocated Channels in an array
218 */
219 /* DMA/QDMA Channel */
220 DAT_allocatedChannels[i].paramNo = chaNum;
221 /* TCC */
222 DAT_allocatedChannels[i].tccNo = tccNum;
223 }
225 return 1;
226 }
228 /*
229 * ======== DAT_close =========
230 * Close the DAT module
231 */
232 void DAT_close() {
233 int i = 0;
235 /*
236 * Ensure DAT_open was called
237 */
238 _dat_critical_section_enter();
239 if (DAT_EDMA3LLD_openFlag == 0)
240 {
241 _dat_critical_section_exit();
242 return;
243 }
244 DAT_EDMA3LLD_openFlag = 0;
245 _dat_critical_section_exit();
247 /*
248 * Wait for all pending transfers to complete
249 */
250 DAT_wait(DAT_XFRID_WAITALL);
252 /*
253 * Free all requested channels
254 */
255 for(i=0; i < DAT_EDMA3LLD_numAllocatedChannels; i++) {
256 EDMA3_DRV_freeChannel(DAT_EDMA3LLD_hEdma,
257 DAT_allocatedChannels[i].paramNo);
258 DAT_allocatedChannels[i].paramNo = DAT_INVALID_ID;
259 DAT_allocatedChannels[i].tccNo = DAT_INVALID_ID;
260 }
262 }
264 /*
265 * ======== DAT_copy =========
266 * One dimensional copy from source to destination of byteCnt bytes
267 */
268 Uint32 DAT_copy(void *src, void *dst, Uint16 byteCnt ) {
269 Uint32 chNum = 0;
270 Uint32 tccNum = 0;
271 EDMA3_DRV_PaRAMRegs paramSet = {0,0,0,0,0,0,0,0,0,0,0,0};
273 /*
274 * An alternate way to setup the params
275 * EDMA3_DRV_PaRAMRegs param;
276 * const EDMA3_DRV_PaRAMRegs *newPaRAM = ¶m;
277 */
279 /*
280 * Obtain a free channel
281 * This call spins till a free channel is obtained
282 */
283 chNum = _getFreeChannel(&tccNum);
285 /*
286 * Set up Transfer Paramters for this channel
287 */
288 /* Fill the PaRAM Set with transfer specific information */
289 paramSet.srcAddr = (unsigned int)(src);
290 paramSet.destAddr = (unsigned int)(dst);
291 paramSet.srcBIdx = 0;
292 paramSet.destBIdx = 0;
293 paramSet.srcCIdx = 0;
294 paramSet.destCIdx = 0;
295 paramSet.aCnt = byteCnt;
296 paramSet.bCnt = 1;
297 /* Trigger word is CCNT */
298 paramSet.cCnt = 1;
299 paramSet.bCntReload = 0;
300 paramSet.linkAddr = 0xFFFFu;
301 /* Src & Dest are in INCR modes */
302 paramSet.opt &= 0xFFFFFFFCu;
303 /* Program the TCC */
304 paramSet.opt |= ((tccNum << OPT_TCC_SHIFT) & OPT_TCC_MASK);
305 /* Enable Final transfer completion interrupt */
306 paramSet.opt |= (1 << OPT_TCINTEN_SHIFT);
307 /* AB Sync Transfer Mode */
308 paramSet.opt |= (1 << OPT_SYNCDIM_SHIFT);
309 /* Set the static bit */
310 paramSet.opt |= (1 << OPT_STATIC_SHIFT);
312 /*
313 * Set a 1 bit in the TransferComplete register corresponding to the tcc
314 */
315 if (tccNum < 32) {
316 SET_REGISTER32_BIT(TransferCompleteL,tccNum);
317 }
318 else {
319 SET_REGISTER32_BIT(TransferCompleteH,tccNum - 32);
320 }
322 /* trigger the transfer */
323 EDMA3_DRV_setPaRAM(DAT_EDMA3LLD_hEdma, chNum, ¶mSet);
325 return tccNum;
326 }
329 /*
330 * ======== DAT_copy2d =========
331 * 2-dimensional copy from src to dst of lineCnt lines each of length lineLen
332 * bytes. The pitch for the second dimension is linePitch bytes
333 */
334 Uint32 DAT_copy2d(Uint32 type, void *src, void *dst, Uint16 lineLen,
335 Uint16 lineCnt, Uint16 linePitch) {
336 Uint32 chNum = 0;
337 Uint32 tccNum = 0;
338 EDMA3_DRV_PaRAMRegs paramSet = {0,0,0,0,0,0,0,0,0,0,0,0};
340 /*
341 * Obtain a free channel
342 */
343 chNum = _getFreeChannel(&tccNum);
345 /* Fill the PaRAM Set with transfer specific information */
346 paramSet.srcAddr = (unsigned int)(src);
347 paramSet.destAddr = (unsigned int)(dst);
348 paramSet.aCnt = lineLen;
349 paramSet.bCnt = lineCnt;
350 /* Trigger word is CCNT */
351 paramSet.cCnt = 1;
352 paramSet.bCntReload = 0;
353 paramSet.linkAddr = 0xFFFFu;
354 /* Src & Dest are in INCR modes */
355 paramSet.opt &= 0xFFFFFFFCu;
356 /* Program the TCC */
357 paramSet.opt |= ((tccNum << OPT_TCC_SHIFT) & OPT_TCC_MASK);
358 /* Enable Final transfer completion interrupt */
359 paramSet.opt |= (1 << OPT_TCINTEN_SHIFT);
360 /* AB Sync Transfer Mode */
361 paramSet.opt |= (1 << OPT_SYNCDIM_SHIFT);
362 /* Set the static bit */
363 paramSet.opt |= (1 << OPT_STATIC_SHIFT);
365 /*
366 * Depending on type of transfer set the src and dest BIdx
367 * Different types of transfers differ only in the Src and Dst BIdx-es
368 */
369 switch (type) {
370 case DAT_1D2D:
371 paramSet.srcBIdx = lineLen;
372 paramSet.destBIdx = linePitch;
373 paramSet.srcCIdx = 0;
374 paramSet.destCIdx = 0;
375 break;
376 case DAT_2D1D:
377 paramSet.srcBIdx = linePitch;
378 paramSet.destBIdx = lineLen;
379 paramSet.srcCIdx = 0;
380 paramSet.destCIdx = 0;
381 break;
382 case DAT_2D2D:
383 paramSet.srcBIdx = linePitch;
384 paramSet.destBIdx = linePitch;
385 paramSet.srcCIdx = 0;
386 paramSet.destCIdx = 0;
387 break;
388 }
390 /*
391 * Set a 1 bit in the TransferComplete register corresponding to the tcc
392 */
393 if (tccNum < 32) {
394 SET_REGISTER32_BIT(TransferCompleteL,tccNum);
395 }
396 else {
397 SET_REGISTER32_BIT(TransferCompleteH,tccNum - 32);
398 }
400 /* trigger the transfer */
401 EDMA3_DRV_setPaRAM(DAT_EDMA3LLD_hEdma, chNum, ¶mSet);
403 return tccNum;
404 }
407 /*
408 * ======== DAT_fill =========
409 * Fills up dst with byteCnt bytes of the pattern pointed to be 'value'
410 */
411 Uint32 DAT_fill(void *dst, Uint16 byteCnt, Uint32 *value) {
412 Uint32 chNum = 0;
413 Uint32 tccNum = 0;
414 EDMA3_DRV_PaRAMRegs paramSet = {0,0,0,0,0,0,0,0,0,0,0,0};
416 /*
417 * Obtain a free channel
418 */
419 chNum = _getFreeChannel(&tccNum);
421 /* Fill the PaRAM Set with transfer specific information */
422 paramSet.srcAddr = (unsigned int)(value);
423 paramSet.destAddr = (unsigned int)(dst);
424 paramSet.srcBIdx = 0;
425 paramSet.destBIdx = 8;
426 paramSet.srcCIdx = 0;
427 paramSet.destCIdx = 0;
428 paramSet.aCnt = 8;
429 paramSet.bCnt = byteCnt>>3;
430 /* Trigger word is CCNT */
431 paramSet.cCnt = 1;
432 paramSet.bCntReload = 0;
433 paramSet.linkAddr = 0xFFFFu;
434 /* Src & Dest are in INCR modes */
435 paramSet.opt &= 0xFFFFFFFCu;
436 /* Program the TCC */
437 paramSet.opt |= ((tccNum << OPT_TCC_SHIFT) & OPT_TCC_MASK);
438 /* Enable Final transfer completion interrupt */
439 paramSet.opt |= (1 << OPT_TCINTEN_SHIFT);
440 /* AB Sync Transfer Mode */
441 paramSet.opt |= (1 << OPT_SYNCDIM_SHIFT);
442 /* Set the static bit */
443 paramSet.opt |= (1 << OPT_STATIC_SHIFT);
445 /*
446 * Set a 1 bit in the TransferComplete register corresponding to the tcc
447 */
448 if (tccNum < 32) {
449 SET_REGISTER32_BIT(TransferCompleteL,tccNum);
450 }
451 else {
452 SET_REGISTER32_BIT(TransferCompleteH,tccNum - 32);
453 }
455 /* trigger the transfer */
456 EDMA3_DRV_setPaRAM(DAT_EDMA3LLD_hEdma, chNum, ¶mSet);
458 return tccNum;
459 }
463 /*
464 * ======== DAT_wait =========
465 * Wait for the transfer identified by waitId, to complete
466 */
467 void DAT_wait(Uint32 waitId) {
468 int i;
469 Uint32 tcc;
471 /*
472 * If both the registers are zero, we're done !!
473 */
474 if (0x0 == (TransferCompleteL | TransferCompleteH)) {
475 return;
476 }
478 /*
479 * Check if we need to wait for all transfers or just this one ?
480 */
481 if (DAT_XFRID_WAITALL == waitId) {
482 for (i = 0 ; i < DAT_EDMA3LLD_numAllocatedChannels; i++) {
483 tcc = DAT_allocatedChannels[i].tccNo;
484 if (tcc < 32) {
485 if (GET_REGISTER32_BIT(TransferCompleteL, tcc)) {
486 EDMA3_DRV_waitAndClearTcc (DAT_EDMA3LLD_hEdma, tcc);
487 CLEAR_REGISTER32_BIT(TransferCompleteL, tcc);
488 }
489 } else {
490 if (GET_REGISTER32_BIT(TransferCompleteH, tcc - 32)) {
491 EDMA3_DRV_waitAndClearTcc (DAT_EDMA3LLD_hEdma, tcc);
492 CLEAR_REGISTER32_BIT(TransferCompleteH, tcc - 32);
493 }
494 }
495 }
496 } else {
497 EDMA3_DRV_waitAndClearTcc (DAT_EDMA3LLD_hEdma, waitId);
499 /*
500 * Mark zero in bit position tccNum
501 */
502 if (waitId < 32) {
503 CLEAR_REGISTER32_BIT(TransferCompleteL, waitId );
504 }
505 else {
506 CLEAR_REGISTER32_BIT(TransferCompleteH, waitId -32 );
507 }
508 }
509 }
511 /*
512 * ======== DAT_busy =========
513 * Check the busy status of transfer identified by waitId
514 */
515 int DAT_busy(Uint32 waitId) {
516 Uint16 status = 0;
518 /*
519 * Check if the particular transfer has completed by returning the status
520 * from the itnernal completion register
521 */
522 if (waitId < 32) {
523 if (GET_REGISTER32_BIT(TransferCompleteL,waitId)) {
524 /** Bit is still set, check in the IPR and clear it
525 * if the xfer has finished. Clear the local reg too.
526 * Else leave everything like that
527 */
528 EDMA3_DRV_checkAndClearTcc(DAT_EDMA3LLD_hEdma, waitId, &status);
529 if (status == 1) {
530 /* xfer finished, update local reg */
531 CLEAR_REGISTER32_BIT(TransferCompleteL, waitId);
532 return 0;
533 } else {
534 /* xfer not finished, leave... */
535 return 1;
536 }
538 } else
539 return 0;
540 }
541 else {
542 if (GET_REGISTER32_BIT(TransferCompleteH,waitId - 32)) {
543 EDMA3_DRV_checkAndClearTcc(DAT_EDMA3LLD_hEdma, waitId, &status);
544 if (status == 1) {
545 CLEAR_REGISTER32_BIT(TransferCompleteH, waitId - 32);
546 return 0;
547 } else {
548 return 1;
549 }
550 } else
551 return 0;
552 }
553 }
555 /*
556 * static function definitions
557 */
559 /*
560 * ======== _getFreeChannel =========
561 * Used to obtain the next available channel to set up a new transfer
562 * Function spins till a channel becomes available
563 */
564 static inline Uint32 _getFreeChannel(Uint32 *tccNum) {
565 Uint32 chNum,index ;
566 Uint16 status=0;
568 /*
569 * Start looking for available channels from the index after the one
570 * that was allocated previously
571 */
572 index = (lastAllocatedIndex + 1)%(DAT_EDMA3LLD_numAllocatedChannels);
574 /*
575 * Spins till a free bit in TransferComplete is found
576 */
577 while (1) {
578 *tccNum = DAT_allocatedChannels[index].tccNo;
580 if (*tccNum < 32) {
581 if((GET_REGISTER32_BIT(TransferCompleteL,*tccNum)) == 0) {
582 /* tcc not allocated or already freed */
583 chNum = DAT_allocatedChannels[index].paramNo;
584 lastAllocatedIndex = index;
585 return chNum;
586 } else {
587 /** Tcc allocated but not yet freed, check the IPR bit now
588 * corresponding to this tcc
589 * if the bit is set, it means that xfer has finished
590 * so clear it and use this tcc
591 * else leave it like that
592 */
593 EDMA3_DRV_checkAndClearTcc(DAT_EDMA3LLD_hEdma, *tccNum, &status);
594 if (1 == status)
595 {
596 /* xfer completed, IPR cleared too */
597 chNum = DAT_allocatedChannels[index].paramNo;
598 lastAllocatedIndex = index;
600 /* clear the reg too */
601 CLEAR_REGISTER32_BIT(TransferCompleteL, *tccNum);
602 return chNum;
603 }
604 }
606 }
607 else {
608 if((GET_REGISTER32_BIT(TransferCompleteH,*tccNum - 32)) == 0) {
609 chNum = DAT_allocatedChannels[index].paramNo;
610 lastAllocatedIndex = index;
611 return chNum;
612 } else {
613 EDMA3_DRV_checkAndClearTcc(DAT_EDMA3LLD_hEdma, *tccNum, &status);
614 if (1 == status)
615 {
616 chNum = DAT_allocatedChannels[index].paramNo;
617 lastAllocatedIndex = index;
619 CLEAR_REGISTER32_BIT(TransferCompleteH, *tccNum - 32);
620 return chNum;
621 }
622 }
623 }
625 /*
626 * Increment index
627 */
628 index = (index + 1)%(DAT_EDMA3LLD_numAllocatedChannels);
629 }
630 }