Merge branch 'lpc32xx/dts' of git://git.antcom.de/linux-2.6 into next/dt
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / arm / mach-bcmring / csp / dmac / dmacHw.c
1 /*****************************************************************************
2 * Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2, available at
7 * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8 *
9 * Notwithstanding the above, under no circumstances may you combine this
10 * software in any way with any other Broadcom software provided under a
11 * license other than the GPL, without Broadcom's express prior written
12 * consent.
13 *****************************************************************************/
14
15 /****************************************************************************/
16 /**
17 *  @file    dmacHw.c
18 *
19 *  @brief   Low level DMA controller driver routines
20 *
21 *  @note
22 *
23 *   These routines provide basic DMA functionality only.
24 */
25 /****************************************************************************/
26
27 /* ---- Include Files ---------------------------------------------------- */
28 #include <csp/stdint.h>
29 #include <csp/string.h>
30 #include <stddef.h>
31
32 #include <csp/dmacHw.h>
33 #include <mach/csp/dmacHw_reg.h>
34 #include <mach/csp/dmacHw_priv.h>
35 #include <mach/csp/chipcHw_inline.h>
36
37 /* ---- External Function Prototypes ------------------------------------- */
38
39 /* Allocate DMA control blocks */
40 dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
41
42 uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
43 uint32_t dmaChannelCount_1 = dmacHw_MAX_CHANNEL_COUNT / 2;
44
45 /****************************************************************************/
46 /**
47 *  @brief   Get maximum FIFO for a DMA channel
48 *
49 *  @return  Maximum allowable FIFO size
50 *
51 *
52 */
53 /****************************************************************************/
54 static uint32_t GetFifoSize(dmacHw_HANDLE_t handle      /*   [ IN ] DMA Channel handle */
55     ) {
56         uint32_t val = 0;
57         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
58         dmacHw_MISC_t *pMiscReg =
59             (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
60
61         switch (pCblk->channel) {
62         case 0:
63                 val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
64                 break;
65         case 1:
66                 val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
67                 break;
68         case 2:
69                 val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
70                 break;
71         case 3:
72                 val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
73                 break;
74         case 4:
75                 val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
76                 break;
77         case 5:
78                 val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
79                 break;
80         case 6:
81                 val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
82                 break;
83         case 7:
84                 val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
85                 break;
86         }
87
88         if (val <= 0x4) {
89                 return 8 << val;
90         } else {
91                 dmacHw_ASSERT(0);
92         }
93         return 0;
94 }
95
96 /****************************************************************************/
97 /**
98 *  @brief   Program channel register to initiate transfer
99 *
100 *  @return  void
101 *
102 *
103 *  @note
104 *     - Descriptor buffer MUST ALWAYS be flushed before calling this function
105 *     - This function should also be called from ISR to program the channel with
106 *       pending descriptors
107 */
108 /****************************************************************************/
109 void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle,    /*   [ IN ] DMA Channel handle */
110                              dmacHw_CONFIG_t *pConfig,  /*   [ IN ] Configuration settings */
111                              void *pDescriptor  /*   [ IN ] Descriptor buffer */
112     ) {
113         dmacHw_DESC_RING_t *pRing;
114         dmacHw_DESC_t *pProg;
115         dmacHw_CBLK_t *pCblk;
116
117         pCblk = dmacHw_HANDLE_TO_CBLK(handle);
118         pRing = dmacHw_GET_DESC_RING(pDescriptor);
119
120         if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
121                 /* Not safe yet to program the channel */
122                 return;
123         }
124
125         if (pCblk->varDataStarted) {
126                 if (pCblk->descUpdated) {
127                         pCblk->descUpdated = 0;
128                         pProg =
129                             (dmacHw_DESC_t *) ((uint32_t)
130                                                dmacHw_REG_LLP(pCblk->module,
131                                                               pCblk->channel) +
132                                                pRing->virt2PhyOffset);
133
134                         /* Load descriptor if not loaded */
135                         if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) {
136                                 dmacHw_SET_SAR(pCblk->module, pCblk->channel,
137                                                pProg->sar);
138                                 dmacHw_SET_DAR(pCblk->module, pCblk->channel,
139                                                pProg->dar);
140                                 dmacHw_REG_CTL_LO(pCblk->module,
141                                                   pCblk->channel) =
142                                     pProg->ctl.lo;
143                                 dmacHw_REG_CTL_HI(pCblk->module,
144                                                   pCblk->channel) =
145                                     pProg->ctl.hi;
146                         } else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) {
147                                 /* Return as end descriptor is processed */
148                                 return;
149                         } else {
150                                 dmacHw_ASSERT(0);
151                         }
152                 } else {
153                         return;
154                 }
155         } else {
156                 if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) {
157                         /* Do not make a single chain, rather process one descriptor at a time */
158                         pProg = pRing->pHead;
159                         /* Point to the next descriptor for next iteration */
160                         dmacHw_NEXT_DESC(pRing, pHead);
161                 } else {
162                         /* Return if no more pending descriptor */
163                         if (pRing->pEnd == NULL) {
164                                 return;
165                         }
166
167                         pProg = pRing->pProg;
168                         if (pConfig->transferMode ==
169                             dmacHw_TRANSFER_MODE_CONTINUOUS) {
170                                 /* Make sure a complete ring can be formed */
171                                 dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd->
172                                               llp == pRing->pProg);
173                                 /* Make sure pProg pointing to the pHead */
174                                 dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg ==
175                                               pRing->pHead);
176                                 /* Make a complete ring */
177                                 do {
178                                         pRing->pProg->ctl.lo |=
179                                             (dmacHw_REG_CTL_LLP_DST_EN |
180                                              dmacHw_REG_CTL_LLP_SRC_EN);
181                                         pRing->pProg =
182                                             (dmacHw_DESC_t *) pRing->pProg->llp;
183                                 } while (pRing->pProg != pRing->pHead);
184                         } else {
185                                 /* Make a single long chain */
186                                 while (pRing->pProg != pRing->pEnd) {
187                                         pRing->pProg->ctl.lo |=
188                                             (dmacHw_REG_CTL_LLP_DST_EN |
189                                              dmacHw_REG_CTL_LLP_SRC_EN);
190                                         pRing->pProg =
191                                             (dmacHw_DESC_t *) pRing->pProg->llp;
192                                 }
193                         }
194                 }
195
196                 /* Program the channel registers */
197                 dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar);
198                 dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar);
199                 dmacHw_SET_LLP(pCblk->module, pCblk->channel,
200                                (uint32_t) pProg - pRing->virt2PhyOffset);
201                 dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) =
202                     pProg->ctl.lo;
203                 dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) =
204                     pProg->ctl.hi;
205                 if (pRing->pEnd) {
206                         /* Remember the descriptor to use next */
207                         pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp;
208                 }
209                 /* Indicate no more pending descriptor  */
210                 pRing->pEnd = (dmacHw_DESC_t *) NULL;
211         }
212         /* Start DMA operation */
213         dmacHw_DMA_START(pCblk->module, pCblk->channel);
214 }
215
216 /****************************************************************************/
217 /**
218 *  @brief   Initializes DMA
219 *
220 *  This function initializes DMA CSP driver
221 *
222 *  @note
223 *     Must be called before using any DMA channel
224 */
225 /****************************************************************************/
226 void dmacHw_initDma(void)
227 {
228
229         uint32_t i = 0;
230
231         dmaChannelCount_0 = dmacHw_GET_NUM_CHANNEL(0);
232         dmaChannelCount_1 = dmacHw_GET_NUM_CHANNEL(1);
233
234         /* Enable access to the DMA block */
235         chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0);
236         chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1);
237
238         if ((dmaChannelCount_0 + dmaChannelCount_1) > dmacHw_MAX_CHANNEL_COUNT) {
239                 dmacHw_ASSERT(0);
240         }
241
242         memset((void *)dmacHw_gCblk, 0,
243                sizeof(dmacHw_CBLK_t) * (dmaChannelCount_0 + dmaChannelCount_1));
244         for (i = 0; i < dmaChannelCount_0; i++) {
245                 dmacHw_gCblk[i].module = 0;
246                 dmacHw_gCblk[i].channel = i;
247         }
248         for (i = 0; i < dmaChannelCount_1; i++) {
249                 dmacHw_gCblk[i + dmaChannelCount_0].module = 1;
250                 dmacHw_gCblk[i + dmaChannelCount_0].channel = i;
251         }
252 }
253
254 /****************************************************************************/
255 /**
256 *  @brief   Exit function for  DMA
257 *
258 *  This function isolates DMA from the system
259 *
260 */
261 /****************************************************************************/
262 void dmacHw_exitDma(void)
263 {
264         /* Disable access to the DMA block */
265         chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0);
266         chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1);
267 }
268
269 /****************************************************************************/
270 /**
271 *  @brief   Gets a handle to a DMA channel
272 *
273 *  This function returns a handle, representing a control block of a particular DMA channel
274 *
275 *  @return  -1       - On Failure
276 *            handle  - On Success, representing a channel control block
277 *
278 *  @note
279 *     None  Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
280 */
281 /****************************************************************************/
282 dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId   /* [ IN ] DMA Channel Id */
283     ) {
284         int idx;
285
286         switch ((channelId >> 8)) {
287         case 0:
288                 dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_0);
289                 idx = (channelId & 0xff);
290                 break;
291         case 1:
292                 dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_1);
293                 idx = dmaChannelCount_0 + (channelId & 0xff);
294                 break;
295         default:
296                 dmacHw_ASSERT(0);
297                 return (dmacHw_HANDLE_t) -1;
298         }
299
300         return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[idx]);
301 }
302
303 /****************************************************************************/
304 /**
305 *  @brief   Initializes a DMA channel for use
306 *
307 *  This function initializes and resets a DMA channel for use
308 *
309 *  @return  -1     - On Failure
310 *            0     - On Success
311 *
312 *  @note
313 *     None
314 */
315 /****************************************************************************/
316 int dmacHw_initChannel(dmacHw_HANDLE_t handle   /*   [ IN ] DMA Channel handle */
317     ) {
318         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
319         int module = pCblk->module;
320         int channel = pCblk->channel;
321
322         /* Reinitialize the control block */
323         memset((void *)pCblk, 0, sizeof(dmacHw_CBLK_t));
324         pCblk->module = module;
325         pCblk->channel = channel;
326
327         /* Enable DMA controller */
328         dmacHw_DMA_ENABLE(pCblk->module);
329         /* Reset DMA channel */
330         dmacHw_RESET_CONTROL_LO(pCblk->module, pCblk->channel);
331         dmacHw_RESET_CONTROL_HI(pCblk->module, pCblk->channel);
332         dmacHw_RESET_CONFIG_LO(pCblk->module, pCblk->channel);
333         dmacHw_RESET_CONFIG_HI(pCblk->module, pCblk->channel);
334
335         /* Clear all raw interrupt status */
336         dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
337         dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
338         dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
339
340         /* Mask event specific interrupts */
341         dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
342         dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
343         dmacHw_STRAN_INT_DISABLE(pCblk->module, pCblk->channel);
344         dmacHw_DTRAN_INT_DISABLE(pCblk->module, pCblk->channel);
345         dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
346
347         return 0;
348 }
349
350 /****************************************************************************/
351 /**
352 *  @brief  Finds amount of memory required to form a descriptor ring
353 *
354 *
355 *  @return   Number of bytes required to form a descriptor ring
356 *
357 *
358 */
359 /****************************************************************************/
360 uint32_t dmacHw_descriptorLen(uint32_t descCnt  /* [ IN ] Number of descriptor in the ring */
361     ) {
362         /* Need extra 4 byte to ensure 32 bit alignment  */
363         return (descCnt * sizeof(dmacHw_DESC_t)) + sizeof(dmacHw_DESC_RING_t) +
364                 sizeof(uint32_t);
365 }
366
367 /****************************************************************************/
368 /**
369 *  @brief   Initializes descriptor ring
370 *
371 *  This function will initializes the descriptor ring of a DMA channel
372 *
373 *
374 *  @return   -1 - On failure
375 *             0 - On success
376 *  @note
377 *     - "len" parameter should be obtained from "dmacHw_descriptorLen"
378 *     - Descriptor buffer MUST be 32 bit aligned and uncached as it is
379 *       accessed by ARM and DMA
380 */
381 /****************************************************************************/
382 int dmacHw_initDescriptor(void *pDescriptorVirt,        /*  [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
383                           uint32_t descriptorPhyAddr,   /*  [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
384                           uint32_t len, /*  [ IN ] Size of the pBuf */
385                           uint32_t num  /*  [ IN ] Number of descriptor in the ring */
386     ) {
387         uint32_t i;
388         dmacHw_DESC_RING_t *pRing;
389         dmacHw_DESC_t *pDesc;
390
391         /* Check the alignment of the descriptor */
392         if ((uint32_t) pDescriptorVirt & 0x00000003) {
393                 dmacHw_ASSERT(0);
394                 return -1;
395         }
396
397         /* Check if enough space has been allocated for descriptor ring */
398         if (len < dmacHw_descriptorLen(num)) {
399                 return -1;
400         }
401
402         pRing = dmacHw_GET_DESC_RING(pDescriptorVirt);
403         pRing->pHead =
404             (dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t));
405         pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
406         pRing->pProg = dmacHw_DESC_INIT;
407         /* Initialize link item chain, starting from the head */
408         pDesc = pRing->pHead;
409         /* Find the offset between virtual to physical address */
410         pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr;
411
412         /* Form the descriptor ring */
413         for (i = 0; i < num - 1; i++) {
414                 /* Clear link list item */
415                 memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
416                 /* Point to the next item in the physical address */
417                 pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset;
418                 /* Point to the next item in the virtual address */
419                 pDesc->llp = (uint32_t) (pDesc + 1);
420                 /* Mark descriptor is ready to use */
421                 pDesc->ctl.hi = dmacHw_DESC_FREE;
422                 /* Look into next link list item */
423                 pDesc++;
424         }
425
426         /* Clear last link list item */
427         memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
428         /* Last item pointing to the first item in the
429            physical address to complete the ring */
430         pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset;
431         /* Last item pointing to the first item in the
432            virtual address to complete the ring
433          */
434         pDesc->llp = (uint32_t) pRing->pHead;
435         /* Mark descriptor is ready to use */
436         pDesc->ctl.hi = dmacHw_DESC_FREE;
437         /* Set the number of descriptors in the ring */
438         pRing->num = num;
439         return 0;
440 }
441
442 /****************************************************************************/
443 /**
444 *  @brief   Configure DMA channel
445 *
446 *  @return  0  : On success
447 *           -1 : On failure
448 */
449 /****************************************************************************/
450 int dmacHw_configChannel(dmacHw_HANDLE_t handle,        /*   [ IN ] DMA Channel handle */
451                          dmacHw_CONFIG_t *pConfig       /*   [ IN ] Configuration settings */
452     ) {
453         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
454         uint32_t cfgHigh = 0;
455         int srcTrSize;
456         int dstTrSize;
457
458         pCblk->varDataStarted = 0;
459         pCblk->userData = NULL;
460
461         /* Configure
462            - Burst transaction when enough data in available in FIFO
463            - AHB Access protection 1
464            - Source and destination peripheral ports
465          */
466         cfgHigh =
467             dmacHw_REG_CFG_HI_FIFO_ENOUGH | dmacHw_REG_CFG_HI_AHB_HPROT_1 |
468             dmacHw_SRC_PERI_INTF(pConfig->
469                                  srcPeripheralPort) |
470             dmacHw_DST_PERI_INTF(pConfig->dstPeripheralPort);
471         /* Set priority */
472         dmacHw_SET_CHANNEL_PRIORITY(pCblk->module, pCblk->channel,
473                                     pConfig->channelPriority);
474
475         if (pConfig->dstStatusRegisterAddress != 0) {
476                 /* Destination status update enable */
477                 cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_DST_STAT;
478                 /* Configure status registers */
479                 dmacHw_SET_DSTATAR(pCblk->module, pCblk->channel,
480                                    pConfig->dstStatusRegisterAddress);
481         }
482
483         if (pConfig->srcStatusRegisterAddress != 0) {
484                 /* Source status update enable */
485                 cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_SRC_STAT;
486                 /* Source status update enable */
487                 dmacHw_SET_SSTATAR(pCblk->module, pCblk->channel,
488                                    pConfig->srcStatusRegisterAddress);
489         }
490         /* Configure the config high register */
491         dmacHw_GET_CONFIG_HI(pCblk->module, pCblk->channel) = cfgHigh;
492
493         /* Clear all raw interrupt status */
494         dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
495         dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
496         dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
497
498         /* Configure block interrupt */
499         if (pConfig->blockTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
500                 dmacHw_BLOCK_INT_ENABLE(pCblk->module, pCblk->channel);
501         } else {
502                 dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
503         }
504         /* Configure complete transfer interrupt */
505         if (pConfig->completeTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
506                 dmacHw_TRAN_INT_ENABLE(pCblk->module, pCblk->channel);
507         } else {
508                 dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
509         }
510         /* Configure error interrupt */
511         if (pConfig->errorInterrupt == dmacHw_INTERRUPT_ENABLE) {
512                 dmacHw_ERROR_INT_ENABLE(pCblk->module, pCblk->channel);
513         } else {
514                 dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
515         }
516         /* Configure gather register */
517         if (pConfig->srcGatherWidth) {
518                 srcTrSize =
519                     dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
520                 if (!
521                     ((pConfig->srcGatherWidth % srcTrSize)
522                      && (pConfig->srcGatherJump % srcTrSize))) {
523                         dmacHw_REG_SGR_LO(pCblk->module, pCblk->channel) =
524                             ((pConfig->srcGatherWidth /
525                               srcTrSize) << 20) | (pConfig->srcGatherJump /
526                                                    srcTrSize);
527                 } else {
528                         return -1;
529                 }
530         }
531         /* Configure scatter register */
532         if (pConfig->dstScatterWidth) {
533                 dstTrSize =
534                     dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
535                 if (!
536                     ((pConfig->dstScatterWidth % dstTrSize)
537                      && (pConfig->dstScatterJump % dstTrSize))) {
538                         dmacHw_REG_DSR_LO(pCblk->module, pCblk->channel) =
539                             ((pConfig->dstScatterWidth /
540                               dstTrSize) << 20) | (pConfig->dstScatterJump /
541                                                    dstTrSize);
542                 } else {
543                         return -1;
544                 }
545         }
546         return 0;
547 }
548
549 /****************************************************************************/
550 /**
551 *  @brief   Indicates whether DMA transfer is in progress or completed
552 *
553 *  @return   DMA transfer status
554 *          dmacHw_TRANSFER_STATUS_BUSY:         DMA Transfer ongoing
555 *          dmacHw_TRANSFER_STATUS_DONE:         DMA Transfer completed
556 *          dmacHw_TRANSFER_STATUS_ERROR:        DMA Transfer error
557 *
558 */
559 /****************************************************************************/
560 dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle        /*   [ IN ] DMA Channel handle */
561     ) {
562         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
563
564         if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
565                 return dmacHw_TRANSFER_STATUS_BUSY;
566         } else if (dmacHw_REG_INT_RAW_ERROR(pCblk->module) &
567                    (0x00000001 << pCblk->channel)) {
568                 return dmacHw_TRANSFER_STATUS_ERROR;
569         }
570
571         return dmacHw_TRANSFER_STATUS_DONE;
572 }
573
574 /****************************************************************************/
575 /**
576 *  @brief   Set descriptors for known data length
577 *
578 *  When DMA has to work as a flow controller, this function prepares the
579 *  descriptor chain to transfer data
580 *
581 *  from:
582 *          - Memory to memory
583 *          - Peripheral to memory
584 *          - Memory to Peripheral
585 *          - Peripheral to Peripheral
586 *
587 *  @return   -1 - On failure
588 *             0 - On success
589 *
590 */
591 /****************************************************************************/
592 int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig,  /*   [ IN ] Configuration settings */
593                              void *pDescriptor, /*   [ IN ] Descriptor buffer */
594                              void *pSrcAddr,    /*   [ IN ] Source (Peripheral/Memory) address */
595                              void *pDstAddr,    /*   [ IN ] Destination (Peripheral/Memory) address */
596                              size_t dataLen     /*   [ IN ] Data length in bytes */
597     ) {
598         dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
599         dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
600         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
601         dmacHw_DESC_t *pStart;
602         dmacHw_DESC_t *pProg;
603         int srcTs = 0;
604         int blkTs = 0;
605         int oddSize = 0;
606         int descCount = 0;
607         int count = 0;
608         int dstTrSize = 0;
609         int srcTrSize = 0;
610         uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
611
612         dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
613         srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
614
615         /* Skip Tx if buffer is NULL  or length is unknown */
616         if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
617                 /* Do not initiate transfer */
618                 return -1;
619         }
620
621         /* Ensure scatter and gather are transaction aligned */
622         if ((pConfig->srcGatherWidth % srcTrSize)
623             || (pConfig->dstScatterWidth % dstTrSize)) {
624                 return -2;
625         }
626
627         /*
628            Background 1: DMAC can not perform DMA if source and destination addresses are
629            not properly aligned with the channel's transaction width. So, for successful
630            DMA transfer, transaction width must be set according to the alignment of the
631            source and destination address.
632          */
633
634         /* Adjust destination transaction width if destination address is not aligned properly */
635         dstTrWidth = pConfig->dstMaxTransactionWidth;
636         while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
637                 dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
638                 dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
639         }
640
641         /* Adjust source transaction width if source address is not aligned properly */
642         srcTrWidth = pConfig->srcMaxTransactionWidth;
643         while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
644                 srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
645                 srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
646         }
647
648         /* Find the maximum transaction per descriptor */
649         if (pConfig->maxDataPerBlock
650             && ((pConfig->maxDataPerBlock / srcTrSize) <
651                 dmacHw_MAX_BLOCKSIZE)) {
652                 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
653         }
654
655         /* Find number of source transactions needed to complete the DMA transfer */
656         srcTs = dataLen / srcTrSize;
657         /* Find the odd number of bytes that need to be transferred as single byte transaction width */
658         if (srcTs && (dstTrSize > srcTrSize)) {
659                 oddSize = dataLen % dstTrSize;
660                 /* Adjust source transaction count due to "oddSize" */
661                 srcTs = srcTs - (oddSize / srcTrSize);
662         } else {
663                 oddSize = dataLen % srcTrSize;
664         }
665         /* Adjust "descCount" due to "oddSize" */
666         if (oddSize) {
667                 descCount++;
668         }
669         /* Find the number of descriptor needed for total "srcTs" */
670         if (srcTs) {
671                 descCount += ((srcTs - 1) / maxBlockSize) + 1;
672         }
673
674         /* Check the availability of "descCount" discriptors in the ring */
675         pProg = pRing->pHead;
676         for (count = 0; (descCount <= pRing->num) && (count < descCount);
677              count++) {
678                 if ((pProg->ctl.hi & dmacHw_DESC_FREE) == 0) {
679                         /* Sufficient descriptors are not available */
680                         return -3;
681                 }
682                 pProg = (dmacHw_DESC_t *) pProg->llp;
683         }
684
685         /* Remember the link list item to program the channel registers */
686         pStart = pProg = pRing->pHead;
687         /* Make a link list with "descCount(=count)" number of descriptors */
688         while (count) {
689                 /* Reset channel control information */
690                 pProg->ctl.lo = 0;
691                 /* Enable source gather if configured */
692                 if (pConfig->srcGatherWidth) {
693                         pProg->ctl.lo |= dmacHw_REG_CTL_SG_ENABLE;
694                 }
695                 /* Enable destination scatter if configured */
696                 if (pConfig->dstScatterWidth) {
697                         pProg->ctl.lo |= dmacHw_REG_CTL_DS_ENABLE;
698                 }
699                 /* Set source and destination address */
700                 pProg->sar = (uint32_t) pSrcAddr;
701                 pProg->dar = (uint32_t) pDstAddr;
702                 /* Use "devCtl" to mark that user memory need to be freed later if needed */
703                 if (pProg == pRing->pHead) {
704                         pProg->devCtl = dmacHw_FREE_USER_MEMORY;
705                 } else {
706                         pProg->devCtl = 0;
707                 }
708
709                 blkTs = srcTs;
710
711                 /* Special treatmeant for last descriptor */
712                 if (count == 1) {
713                         /* Mark the last descriptor */
714                         pProg->ctl.lo &=
715                             ~(dmacHw_REG_CTL_LLP_DST_EN |
716                               dmacHw_REG_CTL_LLP_SRC_EN);
717                         /* Treatment for odd data bytes */
718                         if (oddSize) {
719                                 /* Adjust for single byte transaction width */
720                                 switch (pConfig->transferType) {
721                                 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
722                                         dstTrWidth =
723                                             dmacHw_DST_TRANSACTION_WIDTH_8;
724                                         blkTs =
725                                             (oddSize / srcTrSize) +
726                                             ((oddSize % srcTrSize) ? 1 : 0);
727                                         break;
728                                 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
729                                         srcTrWidth =
730                                             dmacHw_SRC_TRANSACTION_WIDTH_8;
731                                         blkTs = oddSize;
732                                         break;
733                                 case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
734                                         srcTrWidth =
735                                             dmacHw_SRC_TRANSACTION_WIDTH_8;
736                                         dstTrWidth =
737                                             dmacHw_DST_TRANSACTION_WIDTH_8;
738                                         blkTs = oddSize;
739                                         break;
740                                 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
741                                         /* Do not adjust the transaction width  */
742                                         break;
743                                 }
744                         } else {
745                                 srcTs -= blkTs;
746                         }
747                 } else {
748                         if (srcTs / maxBlockSize) {
749                                 blkTs = maxBlockSize;
750                         }
751                         /* Remaining source transactions for next iteration */
752                         srcTs -= blkTs;
753                 }
754                 /* Must have a valid source transactions */
755                 dmacHw_ASSERT(blkTs > 0);
756                 /* Set control information */
757                 if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
758                         pProg->ctl.lo |= pConfig->transferType |
759                             pConfig->srcUpdate |
760                             pConfig->dstUpdate |
761                             srcTrWidth |
762                             dstTrWidth |
763                             pConfig->srcMaxBurstWidth |
764                             pConfig->dstMaxBurstWidth |
765                             pConfig->srcMasterInterface |
766                             pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
767                 } else {
768                         uint32_t transferType = 0;
769                         switch (pConfig->transferType) {
770                         case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
771                                 transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
772                                 break;
773                         case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
774                                 transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
775                                 break;
776                         default:
777                                 dmacHw_ASSERT(0);
778                         }
779                         pProg->ctl.lo |= transferType |
780                             pConfig->srcUpdate |
781                             pConfig->dstUpdate |
782                             srcTrWidth |
783                             dstTrWidth |
784                             pConfig->srcMaxBurstWidth |
785                             pConfig->dstMaxBurstWidth |
786                             pConfig->srcMasterInterface |
787                             pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
788                 }
789
790                 /* Set block transaction size */
791                 pProg->ctl.hi = blkTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
792                 /* Look for next descriptor */
793                 if (count > 1) {
794                         /* Point to the next descriptor */
795                         pProg = (dmacHw_DESC_t *) pProg->llp;
796
797                         /* Update source and destination address for next iteration */
798                         switch (pConfig->transferType) {
799                         case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
800                                 if (pConfig->dstScatterWidth) {
801                                         pDstAddr =
802                                             (char *)pDstAddr +
803                                             blkTs * srcTrSize +
804                                             (((blkTs * srcTrSize) /
805                                               pConfig->dstScatterWidth) *
806                                              pConfig->dstScatterJump);
807                                 } else {
808                                         pDstAddr =
809                                             (char *)pDstAddr +
810                                             blkTs * srcTrSize;
811                                 }
812                                 break;
813                         case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
814                                 if (pConfig->srcGatherWidth) {
815                                         pSrcAddr =
816                                             (char *)pDstAddr +
817                                             blkTs * srcTrSize +
818                                             (((blkTs * srcTrSize) /
819                                               pConfig->srcGatherWidth) *
820                                              pConfig->srcGatherJump);
821                                 } else {
822                                         pSrcAddr =
823                                             (char *)pSrcAddr +
824                                             blkTs * srcTrSize;
825                                 }
826                                 break;
827                         case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
828                                 if (pConfig->dstScatterWidth) {
829                                         pDstAddr =
830                                             (char *)pDstAddr +
831                                             blkTs * srcTrSize +
832                                             (((blkTs * srcTrSize) /
833                                               pConfig->dstScatterWidth) *
834                                              pConfig->dstScatterJump);
835                                 } else {
836                                         pDstAddr =
837                                             (char *)pDstAddr +
838                                             blkTs * srcTrSize;
839                                 }
840
841                                 if (pConfig->srcGatherWidth) {
842                                         pSrcAddr =
843                                             (char *)pDstAddr +
844                                             blkTs * srcTrSize +
845                                             (((blkTs * srcTrSize) /
846                                               pConfig->srcGatherWidth) *
847                                              pConfig->srcGatherJump);
848                                 } else {
849                                         pSrcAddr =
850                                             (char *)pSrcAddr +
851                                             blkTs * srcTrSize;
852                                 }
853                                 break;
854                         case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
855                                 /* Do not adjust the address */
856                                 break;
857                         default:
858                                 dmacHw_ASSERT(0);
859                         }
860                 } else {
861                         /* At the end of transfer "srcTs" must be zero */
862                         dmacHw_ASSERT(srcTs == 0);
863                 }
864                 count--;
865         }
866
867         /* Remember the descriptor to initialize the registers */
868         if (pRing->pProg == dmacHw_DESC_INIT) {
869                 pRing->pProg = pStart;
870         }
871         /* Indicate that the descriptor is updated */
872         pRing->pEnd = pProg;
873         /* Head pointing to the next descriptor */
874         pRing->pHead = (dmacHw_DESC_t *) pProg->llp;
875         /* Update Tail pointer if destination is a peripheral,
876            because no one is going to read from the pTail
877          */
878         if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
879                 pRing->pTail = pRing->pHead;
880         }
881         return 0;
882 }
883
884 /****************************************************************************/
885 /**
886 *  @brief   Provides DMA controller attributes
887 *
888 *
889 *  @return  DMA controller attributes
890 *
891 *  @note
892 *     None
893 */
894 /****************************************************************************/
895 uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle,       /*  [ IN ]  DMA Channel handle */
896                                           dmacHw_CONTROLLER_ATTRIB_e attr       /*  [ IN ]  DMA Controller attribute of type  dmacHw_CONTROLLER_ATTRIB_e */
897     ) {
898         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
899
900         switch (attr) {
901         case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM:
902                 return dmacHw_GET_NUM_CHANNEL(pCblk->module);
903         case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE:
904                 return (1 <<
905                          (dmacHw_GET_MAX_BLOCK_SIZE
906                           (pCblk->module, pCblk->module) + 2)) - 8;
907         case dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM:
908                 return dmacHw_GET_NUM_INTERFACE(pCblk->module);
909         case dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH:
910                 return 32 << dmacHw_GET_CHANNEL_DATA_WIDTH(pCblk->module,
911                                                            pCblk->channel);
912         case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE:
913                 return GetFifoSize(handle);
914         }
915         dmacHw_ASSERT(0);
916         return 0;
917 }