linux/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
<<
>>
Prefs
   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
  36extern 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/****************************************************************************/
  54void 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/****************************************************************************/
  70static 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/****************************************************************************/
 249static 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 controler
 320*           0 : Peripheral is the flow controller
 321*
 322*  @note
 323*     None
 324*/
 325/****************************************************************************/
 326static 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/****************************************************************************/
 356void 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/****************************************************************************/
 389void 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/****************************************************************************/
 410dmacHw_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/****************************************************************************/
 443dmacHw_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/****************************************************************************/
 472int 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 existance 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/****************************************************************************/
 579uint32_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/****************************************************************************/
 606void 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/****************************************************************************/
 630int 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/****************************************************************************/
 679int 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 transfering 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/****************************************************************************/
 791int 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/****************************************************************************/
 866int 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 specif DMA channel
 945*
 946*/
 947/****************************************************************************/
 948void 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/****************************************************************************/
 965void *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/****************************************************************************/
 979void 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/****************************************************************************/
1009void 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