~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c

Version: ~ [ linux-5.3-rc5 ] ~ [ linux-5.2.9 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.67 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.139 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.72 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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_extra.c
 18 *
 19 *  @brief   Extra 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 
 29 #include <csp/stdint.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 
 36 extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];    /* Declared in dmacHw.c */
 37 
 38 /* ---- External Function Prototypes ------------------------------------- */
 39 
 40 /* ---- Internal Use Function Prototypes --------------------------------- */
 41 /****************************************************************************/
 42 /**
 43 *  @brief   Overwrites data length in the descriptor
 44 *
 45 *  This function overwrites data length in the descriptor
 46 *
 47 *
 48 *  @return   void
 49 *
 50 *  @note
 51 *          This is only used for PCM channel
 52 */
 53 /****************************************************************************/
 54 void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig,     /*   [ IN ] Configuration settings */
 55                           void *pDescriptor,    /*   [ IN ] Descriptor buffer */
 56                           size_t dataLen        /*   [ IN ] Data length in bytes */
 57     );
 58 
 59 /****************************************************************************/
 60 /**
 61 *  @brief   Helper function to display DMA registers
 62 *
 63 *  @return  void
 64 *
 65 *
 66 *  @note
 67 *     None
 68 */
 69 /****************************************************************************/
 70 static void DisplayRegisterContents(int module, /*   [ IN ] DMA Controller unit  (0-1) */
 71                                     int channel,        /*   [ IN ] DMA Channel          (0-7) / -1(all) */
 72                                     int (*fpPrint) (const char *, ...)  /*   [ IN ] Callback to the print function */
 73     ) {
 74         int chan;
 75 
 76         (*fpPrint) ("Displaying register content \n\n");
 77         (*fpPrint) ("Module %d: Interrupt raw transfer              0x%X\n",
 78                     module, (uint32_t) (dmacHw_REG_INT_RAW_TRAN(module)));
 79         (*fpPrint) ("Module %d: Interrupt raw block                 0x%X\n",
 80                     module, (uint32_t) (dmacHw_REG_INT_RAW_BLOCK(module)));
 81         (*fpPrint) ("Module %d: Interrupt raw src transfer          0x%X\n",
 82                     module, (uint32_t) (dmacHw_REG_INT_RAW_STRAN(module)));
 83         (*fpPrint) ("Module %d: Interrupt raw dst transfer          0x%X\n",
 84                     module, (uint32_t) (dmacHw_REG_INT_RAW_DTRAN(module)));
 85         (*fpPrint) ("Module %d: Interrupt raw error                 0x%X\n",
 86                     module, (uint32_t) (dmacHw_REG_INT_RAW_ERROR(module)));
 87         (*fpPrint) ("--------------------------------------------------\n");
 88         (*fpPrint) ("Module %d: Interrupt stat transfer             0x%X\n",
 89                     module, (uint32_t) (dmacHw_REG_INT_STAT_TRAN(module)));
 90         (*fpPrint) ("Module %d: Interrupt stat block                0x%X\n",
 91                     module, (uint32_t) (dmacHw_REG_INT_STAT_BLOCK(module)));
 92         (*fpPrint) ("Module %d: Interrupt stat src transfer         0x%X\n",
 93                     module, (uint32_t) (dmacHw_REG_INT_STAT_STRAN(module)));
 94         (*fpPrint) ("Module %d: Interrupt stat dst transfer         0x%X\n",
 95                     module, (uint32_t) (dmacHw_REG_INT_STAT_DTRAN(module)));
 96         (*fpPrint) ("Module %d: Interrupt stat error                0x%X\n",
 97                     module, (uint32_t) (dmacHw_REG_INT_STAT_ERROR(module)));
 98         (*fpPrint) ("--------------------------------------------------\n");
 99         (*fpPrint) ("Module %d: Interrupt mask transfer             0x%X\n",
100                     module, (uint32_t) (dmacHw_REG_INT_MASK_TRAN(module)));
101         (*fpPrint) ("Module %d: Interrupt mask block                0x%X\n",
102                     module, (uint32_t) (dmacHw_REG_INT_MASK_BLOCK(module)));
103         (*fpPrint) ("Module %d: Interrupt mask src transfer         0x%X\n",
104                     module, (uint32_t) (dmacHw_REG_INT_MASK_STRAN(module)));
105         (*fpPrint) ("Module %d: Interrupt mask dst transfer         0x%X\n",
106                     module, (uint32_t) (dmacHw_REG_INT_MASK_DTRAN(module)));
107         (*fpPrint) ("Module %d: Interrupt mask error                0x%X\n",
108                     module, (uint32_t) (dmacHw_REG_INT_MASK_ERROR(module)));
109         (*fpPrint) ("--------------------------------------------------\n");
110         (*fpPrint) ("Module %d: Interrupt clear transfer            0x%X\n",
111                     module, (uint32_t) (dmacHw_REG_INT_CLEAR_TRAN(module)));
112         (*fpPrint) ("Module %d: Interrupt clear block               0x%X\n",
113                     module, (uint32_t) (dmacHw_REG_INT_CLEAR_BLOCK(module)));
114         (*fpPrint) ("Module %d: Interrupt clear src transfer        0x%X\n",
115                     module, (uint32_t) (dmacHw_REG_INT_CLEAR_STRAN(module)));
116         (*fpPrint) ("Module %d: Interrupt clear dst transfer        0x%X\n",
117                     module, (uint32_t) (dmacHw_REG_INT_CLEAR_DTRAN(module)));
118         (*fpPrint) ("Module %d: Interrupt clear error               0x%X\n",
119                     module, (uint32_t) (dmacHw_REG_INT_CLEAR_ERROR(module)));
120         (*fpPrint) ("--------------------------------------------------\n");
121         (*fpPrint) ("Module %d: SW source req                       0x%X\n",
122                     module, (uint32_t) (dmacHw_REG_SW_HS_SRC_REQ(module)));
123         (*fpPrint) ("Module %d: SW dest req                         0x%X\n",
124                     module, (uint32_t) (dmacHw_REG_SW_HS_DST_REQ(module)));
125         (*fpPrint) ("Module %d: SW source signal                    0x%X\n",
126                     module, (uint32_t) (dmacHw_REG_SW_HS_SRC_SGL_REQ(module)));
127         (*fpPrint) ("Module %d: SW dest signal                      0x%X\n",
128                     module, (uint32_t) (dmacHw_REG_SW_HS_DST_SGL_REQ(module)));
129         (*fpPrint) ("Module %d: SW source last                      0x%X\n",
130                     module, (uint32_t) (dmacHw_REG_SW_HS_SRC_LST_REQ(module)));
131         (*fpPrint) ("Module %d: SW dest last                        0x%X\n",
132                     module, (uint32_t) (dmacHw_REG_SW_HS_DST_LST_REQ(module)));
133         (*fpPrint) ("--------------------------------------------------\n");
134         (*fpPrint) ("Module %d: misc config                         0x%X\n",
135                     module, (uint32_t) (dmacHw_REG_MISC_CFG(module)));
136         (*fpPrint) ("Module %d: misc channel enable                 0x%X\n",
137                     module, (uint32_t) (dmacHw_REG_MISC_CH_ENABLE(module)));
138         (*fpPrint) ("Module %d: misc ID                             0x%X\n",
139                     module, (uint32_t) (dmacHw_REG_MISC_ID(module)));
140         (*fpPrint) ("Module %d: misc test                           0x%X\n",
141                     module, (uint32_t) (dmacHw_REG_MISC_TEST(module)));
142 
143         if (channel == -1) {
144                 for (chan = 0; chan < 8; chan++) {
145                         (*fpPrint)
146                             ("--------------------------------------------------\n");
147                         (*fpPrint)
148                             ("Module %d: Channel %d Source                   0x%X\n",
149                              module, chan,
150                              (uint32_t) (dmacHw_REG_SAR(module, chan)));
151                         (*fpPrint)
152                             ("Module %d: Channel %d Destination              0x%X\n",
153                              module, chan,
154                              (uint32_t) (dmacHw_REG_DAR(module, chan)));
155                         (*fpPrint)
156                             ("Module %d: Channel %d LLP                      0x%X\n",
157                              module, chan,
158                              (uint32_t) (dmacHw_REG_LLP(module, chan)));
159                         (*fpPrint)
160                             ("Module %d: Channel %d Control (LO)             0x%X\n",
161                              module, chan,
162                              (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
163                         (*fpPrint)
164                             ("Module %d: Channel %d Control (HI)             0x%X\n",
165                              module, chan,
166                              (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
167                         (*fpPrint)
168                             ("Module %d: Channel %d Source Stats             0x%X\n",
169                              module, chan,
170                              (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
171                         (*fpPrint)
172                             ("Module %d: Channel %d Dest Stats               0x%X\n",
173                              module, chan,
174                              (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
175                         (*fpPrint)
176                             ("Module %d: Channel %d Source Stats Addr        0x%X\n",
177                              module, chan,
178                              (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
179                         (*fpPrint)
180                             ("Module %d: Channel %d Dest Stats Addr          0x%X\n",
181                              module, chan,
182                              (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
183                         (*fpPrint)
184                             ("Module %d: Channel %d Config (LO)              0x%X\n",
185                              module, chan,
186                              (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
187                         (*fpPrint)
188                             ("Module %d: Channel %d Config (HI)              0x%X\n",
189                              module, chan,
190                              (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
191                 }
192         } else {
193                 chan = channel;
194                 (*fpPrint)
195                     ("--------------------------------------------------\n");
196                 (*fpPrint)
197                     ("Module %d: Channel %d Source                   0x%X\n",
198                      module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
199                 (*fpPrint)
200                     ("Module %d: Channel %d Destination              0x%X\n",
201                      module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
202                 (*fpPrint)
203                     ("Module %d: Channel %d LLP                      0x%X\n",
204                      module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
205                 (*fpPrint)
206                     ("Module %d: Channel %d Control (LO)             0x%X\n",
207                      module, chan,
208                      (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
209                 (*fpPrint)
210                     ("Module %d: Channel %d Control (HI)             0x%X\n",
211                      module, chan,
212                      (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
213                 (*fpPrint)
214                     ("Module %d: Channel %d Source Stats             0x%X\n",
215                      module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
216                 (*fpPrint)
217                     ("Module %d: Channel %d Dest Stats               0x%X\n",
218                      module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
219                 (*fpPrint)
220                     ("Module %d: Channel %d Source Stats Addr        0x%X\n",
221                      module, chan,
222                      (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
223                 (*fpPrint)
224                     ("Module %d: Channel %d Dest Stats Addr          0x%X\n",
225                      module, chan,
226                      (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
227                 (*fpPrint)
228                     ("Module %d: Channel %d Config (LO)              0x%X\n",
229                      module, chan,
230                      (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
231                 (*fpPrint)
232                     ("Module %d: Channel %d Config (HI)              0x%X\n",
233                      module, chan,
234                      (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
235         }
236 }
237 
238 /****************************************************************************/
239 /**
240 *  @brief   Helper function to display descriptor ring
241 *
242 *  @return  void
243 *
244 *
245 *  @note
246 *     None
247 */
248 /****************************************************************************/
249 static void DisplayDescRing(void *pDescriptor,  /*   [ IN ] Descriptor buffer */
250                             int (*fpPrint) (const char *, ...)  /*   [ IN ] Callback to the print function */
251     ) {
252         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
253         dmacHw_DESC_t *pStart;
254 
255         if (pRing->pHead == NULL) {
256                 return;
257         }
258 
259         pStart = pRing->pHead;
260 
261         while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
262                 if (pStart == pRing->pHead) {
263                         (*fpPrint) ("Head\n");
264                 }
265                 if (pStart == pRing->pTail) {
266                         (*fpPrint) ("Tail\n");
267                 }
268                 if (pStart == pRing->pProg) {
269                         (*fpPrint) ("Prog\n");
270                 }
271                 if (pStart == pRing->pEnd) {
272                         (*fpPrint) ("End\n");
273                 }
274                 if (pStart == pRing->pFree) {
275                         (*fpPrint) ("Free\n");
276                 }
277                 (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
278                 (*fpPrint) ("sar    0x%0X\n", pStart->sar);
279                 (*fpPrint) ("dar    0x%0X\n", pStart->dar);
280                 (*fpPrint) ("llp    0x%0X\n", pStart->llp);
281                 (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
282                 (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
283                 (*fpPrint) ("sstat  0x%0X\n", pStart->sstat);
284                 (*fpPrint) ("dstat  0x%0X\n", pStart->dstat);
285                 (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
286 
287                 pStart = (dmacHw_DESC_t *) pStart->llp;
288         }
289         if (pStart == pRing->pHead) {
290                 (*fpPrint) ("Head\n");
291         }
292         if (pStart == pRing->pTail) {
293                 (*fpPrint) ("Tail\n");
294         }
295         if (pStart == pRing->pProg) {
296                 (*fpPrint) ("Prog\n");
297         }
298         if (pStart == pRing->pEnd) {
299                 (*fpPrint) ("End\n");
300         }
301         if (pStart == pRing->pFree) {
302                 (*fpPrint) ("Free\n");
303         }
304         (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
305         (*fpPrint) ("sar    0x%0X\n", pStart->sar);
306         (*fpPrint) ("dar    0x%0X\n", pStart->dar);
307         (*fpPrint) ("llp    0x%0X\n", pStart->llp);
308         (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
309         (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
310         (*fpPrint) ("sstat  0x%0X\n", pStart->sstat);
311         (*fpPrint) ("dstat  0x%0X\n", pStart->dstat);
312         (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
313 }
314 
315 /****************************************************************************/
316 /**
317 *  @brief   Check if DMA channel is the flow controller
318 *
319 *  @return  1 : If DMA is a flow controller
320 *           0 : Peripheral is the flow controller
321 *
322 *  @note
323 *     None
324 */
325 /****************************************************************************/
326 static inline int DmaIsFlowController(void *pDescriptor /*   [ IN ] Descriptor buffer */
327     ) {
328         uint32_t ttfc =
329             (dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
330             lo & dmacHw_REG_CTL_TTFC_MASK;
331 
332         switch (ttfc) {
333         case dmacHw_REG_CTL_TTFC_MM_DMAC:
334         case dmacHw_REG_CTL_TTFC_MP_DMAC:
335         case dmacHw_REG_CTL_TTFC_PM_DMAC:
336         case dmacHw_REG_CTL_TTFC_PP_DMAC:
337                 return 1;
338         }
339 
340         return 0;
341 }
342 
343 /****************************************************************************/
344 /**
345 *  @brief   Overwrites data length in the descriptor
346 *
347 *  This function overwrites data length in the descriptor
348 *
349 *
350 *  @return   void
351 *
352 *  @note
353 *          This is only used for PCM channel
354 */
355 /****************************************************************************/
356 void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig,     /*   [ IN ] Configuration settings */
357                           void *pDescriptor,    /*   [ IN ] Descriptor buffer */
358                           size_t dataLen        /*   [ IN ] Data length in bytes */
359     ) {
360         dmacHw_DESC_t *pProg;
361         dmacHw_DESC_t *pHead;
362         int srcTs = 0;
363         int srcTrSize = 0;
364 
365         pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
366         pProg = pHead;
367 
368         srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
369         srcTs = dataLen / srcTrSize;
370         do {
371                 pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
372                 pProg = (dmacHw_DESC_t *) pProg->llp;
373         } while (pProg != pHead);
374 }
375 
376 /****************************************************************************/
377 /**
378 *  @brief   Clears the interrupt
379 *
380 *  This function clears the DMA channel specific interrupt
381 *
382 *
383 *  @return   void
384 *
385 *  @note
386 *     Must be called under the context of ISR
387 */
388 /****************************************************************************/
389 void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle       /* [ IN ] DMA Channel handle */
390     ) {
391         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
392 
393         dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
394         dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
395         dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
396 }
397 
398 /****************************************************************************/
399 /**
400 *  @brief   Returns the cause of channel specific DMA interrupt
401 *
402 *  This function returns the cause of interrupt
403 *
404 *  @return  Interrupt status, each bit representing a specific type of interrupt
405 *
406 *  @note
407 *     Should be called under the context of ISR
408 */
409 /****************************************************************************/
410 dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle      /* [ IN ] DMA Channel handle */
411     ) {
412         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
413         dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
414 
415         if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
416             ((0x00000001 << pCblk->channel))) {
417                 status |= dmacHw_INTERRUPT_STATUS_TRANS;
418         }
419         if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
420             ((0x00000001 << pCblk->channel))) {
421                 status |= dmacHw_INTERRUPT_STATUS_BLOCK;
422         }
423         if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
424             ((0x00000001 << pCblk->channel))) {
425                 status |= dmacHw_INTERRUPT_STATUS_ERROR;
426         }
427 
428         return status;
429 }
430 
431 /****************************************************************************/
432 /**
433 *  @brief   Indentifies a DMA channel causing interrupt
434 *
435 *  This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
436 *
437 *  @return  NULL   : No channel causing DMA interrupt
438 *           ! NULL : Handle to a channel causing DMA interrupt
439 *  @note
440 *     dmacHw_clearInterrupt() must be called with a valid handle after calling this function
441 */
442 /****************************************************************************/
443 dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
444 {
445         uint32_t i;
446 
447         for (i = 0; i < dmaChannelCount_0 + dmaChannelCount_1; i++) {
448                 if ((dmacHw_REG_INT_STAT_TRAN(dmacHw_gCblk[i].module) &
449                      ((0x00000001 << dmacHw_gCblk[i].channel)))
450                     || (dmacHw_REG_INT_STAT_BLOCK(dmacHw_gCblk[i].module) &
451                         ((0x00000001 << dmacHw_gCblk[i].channel)))
452                     || (dmacHw_REG_INT_STAT_ERROR(dmacHw_gCblk[i].module) &
453                         ((0x00000001 << dmacHw_gCblk[i].channel)))
454                     ) {
455                         return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
456                 }
457         }
458         return dmacHw_CBLK_TO_HANDLE(NULL);
459 }
460 
461 /****************************************************************************/
462 /**
463 *  @brief  Estimates number of descriptor needed to perform certain DMA transfer
464 *
465 *
466 *  @return  On failure : -1
467 *           On success : Number of descriptor count
468 *
469 *
470 */
471 /****************************************************************************/
472 int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig,   /*   [ IN ] Configuration settings */
473                                     void *pSrcAddr,     /*   [ IN ] Source (Peripheral/Memory) address */
474                                     void *pDstAddr,     /*   [ IN ] Destination (Peripheral/Memory) address */
475                                     size_t dataLen      /*   [ IN ] Data length in bytes */
476     ) {
477         int srcTs = 0;
478         int oddSize = 0;
479         int descCount = 0;
480         int dstTrSize = 0;
481         int srcTrSize = 0;
482         uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
483         dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
484         dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
485 
486         dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
487         srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
488 
489         /* Skip Tx if buffer is NULL  or length is unknown */
490         if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
491                 /* Do not initiate transfer */
492                 return -1;
493         }
494 
495         /* Ensure scatter and gather are transaction aligned */
496         if (pConfig->srcGatherWidth % srcTrSize
497             || pConfig->dstScatterWidth % dstTrSize) {
498                 return -1;
499         }
500 
501         /*
502            Background 1: DMAC can not perform DMA if source and destination addresses are
503            not properly aligned with the channel's transaction width. So, for successful
504            DMA transfer, transaction width must be set according to the alignment of the
505            source and destination address.
506          */
507 
508         /* Adjust destination transaction width if destination address is not aligned properly */
509         dstTrWidth = pConfig->dstMaxTransactionWidth;
510         while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
511                 dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
512                 dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
513         }
514 
515         /* Adjust source transaction width if source address is not aligned properly */
516         srcTrWidth = pConfig->srcMaxTransactionWidth;
517         while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
518                 srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
519                 srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
520         }
521 
522         /* Find the maximum transaction per descriptor */
523         if (pConfig->maxDataPerBlock
524             && ((pConfig->maxDataPerBlock / srcTrSize) <
525                 dmacHw_MAX_BLOCKSIZE)) {
526                 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
527         }
528 
529         /* Find number of source transactions needed to complete the DMA transfer */
530         srcTs = dataLen / srcTrSize;
531         /* Find the odd number of bytes that need to be transferred as single byte transaction width */
532         if (srcTs && (dstTrSize > srcTrSize)) {
533                 oddSize = dataLen % dstTrSize;
534                 /* Adjust source transaction count due to "oddSize" */
535                 srcTs = srcTs - (oddSize / srcTrSize);
536         } else {
537                 oddSize = dataLen % srcTrSize;
538         }
539         /* Adjust "descCount" due to "oddSize" */
540         if (oddSize) {
541                 descCount++;
542         }
543 
544         /* Find the number of descriptor needed for total "srcTs" */
545         if (srcTs) {
546                 descCount += ((srcTs - 1) / maxBlockSize) + 1;
547         }
548 
549         return descCount;
550 }
551 
552 /****************************************************************************/
553 /**
554 *  @brief   Check the existence of pending descriptor
555 *
556 *  This function confirmes if there is any pending descriptor in the chain
557 *  to program the channel
558 *
559 *  @return  1 : Channel need to be programmed with pending descriptor
560 *           0 : No more pending descriptor to programe the channel
561 *
562 *  @note
563 *     - This function should be called from ISR in case there are pending
564 *       descriptor to program the channel.
565 *
566 *     Example:
567 *
568 *     dmac_isr ()
569 *     {
570 *         ...
571 *         if (dmacHw_descriptorPending (handle))
572 *         {
573 *            dmacHw_initiateTransfer (handle);
574 *         }
575 *     }
576 *
577 */
578 /****************************************************************************/
579 uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle,       /*   [ IN ] DMA Channel handle */
580                                   void *pDescriptor     /*   [ IN ] Descriptor buffer */
581     ) {
582         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
583         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
584 
585         /* Make sure channel is not busy */
586         if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
587                 /* Check if pEnd is not processed */
588                 if (pRing->pEnd) {
589                         /* Something left for processing */
590                         return 1;
591                 }
592         }
593         return 0;
594 }
595 
596 /****************************************************************************/
597 /**
598 *  @brief   Program channel register to stop transfer
599 *
600 *  Ensures the channel is not doing any transfer after calling this function
601 *
602 *  @return  void
603 *
604 */
605 /****************************************************************************/
606 void dmacHw_stopTransfer(dmacHw_HANDLE_t handle /*   [ IN ] DMA Channel handle */
607     ) {
608         dmacHw_CBLK_t *pCblk;
609 
610         pCblk = dmacHw_HANDLE_TO_CBLK(handle);
611 
612         /* Stop the channel */
613         dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
614 }
615 
616 /****************************************************************************/
617 /**
618 *  @brief   Deallocates source or destination memory, allocated
619 *
620 *  This function can be called to deallocate data memory that was DMAed successfully
621 *
622 *  @return  On failure : -1
623 *           On success : Number of buffer freed
624 *
625 *  @note
626 *     This function will be called ONLY, when source OR destination address is pointing
627 *     to dynamic memory
628 */
629 /****************************************************************************/
630 int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig,    /*   [ IN ] Configuration settings */
631                    void *pDescriptor,   /*   [ IN ] Descriptor buffer */
632                    void (*fpFree) (void *)      /*   [ IN ] Function pointer to free data memory */
633     ) {
634         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
635         uint32_t count = 0;
636 
637         if (fpFree == NULL) {
638                 return -1;
639         }
640 
641         while ((pRing->pFree != pRing->pTail)
642                && (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) {
643                 if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) {
644                         /* Identify, which memory to free */
645                         if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
646                                 (*fpFree) ((void *)pRing->pFree->dar);
647                         } else {
648                                 /* Destination was a peripheral */
649                                 (*fpFree) ((void *)pRing->pFree->sar);
650                         }
651                         /* Unmark user memory to indicate it is freed */
652                         pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY;
653                 }
654                 dmacHw_NEXT_DESC(pRing, pFree);
655 
656                 count++;
657         }
658 
659         return count;
660 }
661 
662 /****************************************************************************/
663 /**
664 *  @brief   Prepares descriptor ring, when source peripheral working as a flow controller
665 *
666 *  This function will update the discriptor ring by allocating buffers, when source peripheral
667 *  has to work as a flow controller to transfer data from:
668 *           - Peripheral to memory.
669 *
670 *  @return  On failure : -1
671 *           On success : Number of descriptor updated
672 *
673 *
674 *  @note
675 *     Channel must be configured for peripheral to memory transfer
676 *
677 */
678 /****************************************************************************/
679 int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle,    /*   [ IN ] DMA Channel handle */
680                                      dmacHw_CONFIG_t *pConfig,  /*   [ IN ] Configuration settings */
681                                      void *pDescriptor, /*   [ IN ] Descriptor buffer */
682                                      uint32_t srcAddr,  /*   [ IN ] Source peripheral address */
683                                      void *(*fpAlloc) (int len),        /*   [ IN ] Function pointer  that provides destination memory */
684                                      int len,   /*   [ IN ] Number of bytes "fpAlloc" will allocate for destination */
685                                      int num    /*   [ IN ] Number of descriptor to set */
686     ) {
687         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
688         dmacHw_DESC_t *pProg = NULL;
689         dmacHw_DESC_t *pLast = NULL;
690         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
691         uint32_t dstAddr;
692         uint32_t controlParam;
693         int i;
694 
695         dmacHw_ASSERT(pConfig->transferType ==
696                       dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM);
697 
698         if (num > pRing->num) {
699                 return -1;
700         }
701 
702         pLast = pRing->pEnd;    /* Last descriptor updated */
703         pProg = pRing->pHead;   /* First descriptor in the new list */
704 
705         controlParam = pConfig->srcUpdate |
706             pConfig->dstUpdate |
707             pConfig->srcMaxTransactionWidth |
708             pConfig->dstMaxTransactionWidth |
709             pConfig->srcMasterInterface |
710             pConfig->dstMasterInterface |
711             pConfig->srcMaxBurstWidth |
712             pConfig->dstMaxBurstWidth |
713             dmacHw_REG_CTL_TTFC_PM_PERI |
714             dmacHw_REG_CTL_LLP_DST_EN |
715             dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN;
716 
717         for (i = 0; i < num; i++) {
718                 /* Allocate Rx buffer only for idle descriptor */
719                 if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) ||
720                     ((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail)
721                     ) {
722                         /* Rx descriptor is not idle */
723                         break;
724                 }
725                 /* Set source address */
726                 pRing->pHead->sar = srcAddr;
727                 if (fpAlloc) {
728                         /* Allocate memory for buffer in descriptor */
729                         dstAddr = (uint32_t) (*fpAlloc) (len);
730                         /* Check the destination address */
731                         if (dstAddr == 0) {
732                                 if (i == 0) {
733                                         /* Not a single descriptor is available */
734                                         return -1;
735                                 }
736                                 break;
737                         }
738                         /* Set destination address */
739                         pRing->pHead->dar = dstAddr;
740                 }
741                 /* Set control information */
742                 pRing->pHead->ctl.lo = controlParam;
743                 /* Use "devCtl" to mark the memory that need to be freed later */
744                 pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY;
745                 /* Descriptor is now owned by the channel */
746                 pRing->pHead->ctl.hi = 0;
747                 /* Remember the descriptor last updated */
748                 pRing->pEnd = pRing->pHead;
749                 /* Update next descriptor */
750                 dmacHw_NEXT_DESC(pRing, pHead);
751         }
752 
753         /* Mark the end of the list */
754         pRing->pEnd->ctl.lo &=
755             ~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN);
756         /* Connect the list */
757         if (pLast != pProg) {
758                 pLast->ctl.lo |=
759                     dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN;
760         }
761         /* Mark the descriptors are updated */
762         pCblk->descUpdated = 1;
763         if (!pCblk->varDataStarted) {
764                 /* LLP must be pointing to the first descriptor */
765                 dmacHw_SET_LLP(pCblk->module, pCblk->channel,
766                                (uint32_t) pProg - pRing->virt2PhyOffset);
767                 /* Channel, handling variable data started */
768                 pCblk->varDataStarted = 1;
769         }
770 
771         return i;
772 }
773 
774 /****************************************************************************/
775 /**
776 *  @brief   Read data DMAed to memory
777 *
778 *  This function will read data that has been DMAed to memory while transferring from:
779 *          - Memory to memory
780 *          - Peripheral to memory
781 *
782 *  @param    handle     -
783 *  @param    ppBbuf     -
784 *  @param    pLen       -
785 *
786 *  @return  0 - No more data is available to read
787 *           1 - More data might be available to read
788 *
789 */
790 /****************************************************************************/
791 int dmacHw_readTransferredData(dmacHw_HANDLE_t handle,  /*  [ IN ] DMA Channel handle */
792                                dmacHw_CONFIG_t *pConfig,        /*   [ IN ]  Configuration settings */
793                                void *pDescriptor,       /*   [ IN ] Descriptor buffer */
794                                void **ppBbuf,   /*   [ OUT ] Data received */
795                                size_t *pLlen    /*   [ OUT ] Length of the data received */
796     ) {
797         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
798 
799         (void)handle;
800 
801         if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) {
802                 if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) ||
803                     (pRing->pTail == pRing->pHead)
804                     ) {
805                         /* No receive data available */
806                         *ppBbuf = (char *)NULL;
807                         *pLlen = 0;
808 
809                         return 0;
810                 }
811         }
812 
813         /* Return read buffer and length */
814         *ppBbuf = (char *)pRing->pTail->dar;
815 
816         /* Extract length of the received data */
817         if (DmaIsFlowController(pDescriptor)) {
818                 uint32_t srcTrSize = 0;
819 
820                 switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) {
821                 case dmacHw_REG_CTL_SRC_TR_WIDTH_8:
822                         srcTrSize = 1;
823                         break;
824                 case dmacHw_REG_CTL_SRC_TR_WIDTH_16:
825                         srcTrSize = 2;
826                         break;
827                 case dmacHw_REG_CTL_SRC_TR_WIDTH_32:
828                         srcTrSize = 4;
829                         break;
830                 case dmacHw_REG_CTL_SRC_TR_WIDTH_64:
831                         srcTrSize = 8;
832                         break;
833                 default:
834                         dmacHw_ASSERT(0);
835                 }
836                 /* Calculate length from the block size */
837                 *pLlen =
838                     (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) *
839                     srcTrSize;
840         } else {
841                 /* Extract length from the source peripheral */
842                 *pLlen = pRing->pTail->sstat;
843         }
844 
845         /* Advance tail to next descriptor */
846         dmacHw_NEXT_DESC(pRing, pTail);
847 
848         return 1;
849 }
850 
851 /****************************************************************************/
852 /**
853 *  @brief   Set descriptor carrying control information
854 *
855 *  This function will be used to send specific control information to the device
856 *  using the DMA channel
857 *
858 *
859 *  @return  -1 - On failure
860 *            0 - On success
861 *
862 *  @note
863 *     None
864 */
865 /****************************************************************************/
866 int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig,       /*   [ IN ] Configuration settings */
867                                 void *pDescriptor,      /*   [ IN ] Descriptor buffer */
868                                 uint32_t ctlAddress,    /*   [ IN ] Address of the device control register */
869                                 uint32_t control        /*   [ IN ] Device control information */
870     ) {
871         dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
872 
873         if (ctlAddress == 0) {
874                 return -1;
875         }
876 
877         /* Check the availability of descriptors in the ring */
878         if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) {
879                 return -1;
880         }
881         /* Set control information */
882         pRing->pHead->devCtl = control;
883         /* Set source and destination address */
884         pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl;
885         pRing->pHead->dar = ctlAddress;
886         /* Set control parameters */
887         if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
888                 pRing->pHead->ctl.lo = pConfig->transferType |
889                     dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
890                     dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
891                     dmacHw_SRC_TRANSACTION_WIDTH_32 |
892                     pConfig->dstMaxTransactionWidth |
893                     dmacHw_SRC_BURST_WIDTH_0 |
894                     dmacHw_DST_BURST_WIDTH_0 |
895                     pConfig->srcMasterInterface |
896                     pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
897         } else {
898                 uint32_t transferType = 0;
899                 switch (pConfig->transferType) {
900                 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
901                         transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
902                         break;
903                 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
904                         transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
905                         break;
906                 default:
907                         dmacHw_ASSERT(0);
908                 }
909                 pRing->pHead->ctl.lo = transferType |
910                     dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
911                     dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
912                     dmacHw_SRC_TRANSACTION_WIDTH_32 |
913                     pConfig->dstMaxTransactionWidth |
914                     dmacHw_SRC_BURST_WIDTH_0 |
915                     dmacHw_DST_BURST_WIDTH_0 |
916                     pConfig->srcMasterInterface |
917                     pConfig->dstMasterInterface |
918                     pConfig->flowControler | dmacHw_REG_CTL_INT_EN;
919         }
920 
921         /* Set block transaction size to one 32 bit transaction */
922         pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1;
923 
924         /* Remember the descriptor to initialize the registers */
925         if (pRing->pProg == dmacHw_DESC_INIT) {
926                 pRing->pProg = pRing->pHead;
927         }
928         pRing->pEnd = pRing->pHead;
929 
930         /* Advance the descriptor */
931         dmacHw_NEXT_DESC(pRing, pHead);
932 
933         /* Update Tail pointer if destination is a peripheral */
934         if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
935                 pRing->pTail = pRing->pHead;
936         }
937         return 0;
938 }
939 
940 /****************************************************************************/
941 /**
942 *  @brief   Sets channel specific user data
943 *
944 *  This function associates user data to a specific DMA channel
945 *
946 */
947 /****************************************************************************/
948 void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle,  /*  [ IN ] DMA Channel handle */
949                                void *userData   /*  [ IN ] User data */
950     ) {
951         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
952 
953         pCblk->userData = userData;
954 }
955 
956 /****************************************************************************/
957 /**
958 *  @brief   Gets channel specific user data
959 *
960 *  This function returns user data specific to a DMA channel
961 *
962 *  @return   user data
963 */
964 /****************************************************************************/
965 void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle  /*  [ IN ] DMA Channel handle */
966     ) {
967         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
968 
969         return pCblk->userData;
970 }
971 
972 /****************************************************************************/
973 /**
974 *  @brief   Resets descriptor control information
975 *
976 *  @return  void
977 */
978 /****************************************************************************/
979 void dmacHw_resetDescriptorControl(void *pDescriptor    /*   [ IN ] Descriptor buffer  */
980     ) {
981         int i;
982         dmacHw_DESC_RING_t *pRing;
983         dmacHw_DESC_t *pDesc;
984 
985         pRing = dmacHw_GET_DESC_RING(pDescriptor);
986         pDesc = pRing->pHead;
987 
988         for (i = 0; i < pRing->num; i++) {
989                 /* Mark descriptor is ready to use */
990                 pDesc->ctl.hi = dmacHw_DESC_FREE;
991                 /* Look into next link list item */
992                 pDesc++;
993         }
994         pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
995         pRing->pProg = dmacHw_DESC_INIT;
996 }
997 
998 /****************************************************************************/
999 /**
1000 *  @brief   Displays channel specific registers and other control parameters
1001 *
1002 *  @return  void
1003 *
1004 *
1005 *  @note
1006 *     None
1007 */
1008 /****************************************************************************/
1009 void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle,      /*  [ IN ] DMA Channel handle */
1010                            void *pDescriptor,   /*   [ IN ] Descriptor buffer */
1011                            int (*fpPrint) (const char *, ...)   /*  [ IN ] Print callback function */
1012     ) {
1013         dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
1014 
1015         DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
1016         DisplayDescRing(pDescriptor, fpPrint);
1017 }
1018 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp