SAMV71 Xplained Ultra Software Package 1.5

mcid_dma.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /** \file
00031  *
00032  *  Implement for SD/MMC low level commands.
00033  *
00034  *  \sa \ref hsmci_module, \ref sdmmc_module
00035  */
00036 
00037 /*----------------------------------------------------------------------------
00038  *         Headers
00039  *----------------------------------------------------------------------------*/
00040 
00041 #include "board.h"
00042 #include "sdmmc.h"
00043 
00044 #include <assert.h>
00045 
00046 /*----------------------------------------------------------------------------
00047  *         Local constants
00048  *----------------------------------------------------------------------------*/
00049 /** \addtorgoup mcid_defines
00050  *      @{*/
00051 
00052 /** Enable MCI */
00053 #define MCI_ENABLE(pMciHw)     HSMCI_Enable(pMciHw)
00054 /** Disable MCI */
00055 #define MCI_DISABLE(pMciHw)    HSMCI_Disable(pMciHw)
00056 /** Reset MCI */
00057 #define MCI_RESET(pMciHw)      HSMCI_Reset(pMciHw, 0)
00058 
00059 /** Return halfword(16-bit) count from byte count */
00060 #define toHWCOUNT(byteCnt) (((byteCnt)&0x1) ? (((byteCnt)/2)+1) : ((byteCnt)/2))
00061 /** Return word(32-bit) count from byte count */
00062 #define toWCOUNT(byteCnt)  (((byteCnt)&0x3) ? (((byteCnt)/4)+1) : ((byteCnt)/4))
00063 
00064 
00065 /** Bit mask for status register errors. */
00066 #define STATUS_ERRORS ((uint32_t)(HSMCI_SR_UNRE  \
00067                                   | HSMCI_SR_OVRE \
00068                                   | HSMCI_SR_ACKRCVE \
00069                                   | HSMCI_SR_CSTOE \
00070                                   | HSMCI_SR_DTOE \
00071                                   | HSMCI_SR_DCRCE \
00072                                   | HSMCI_SR_RTOE \
00073                                   | HSMCI_SR_RENDE \
00074                                   | HSMCI_SR_RCRCE \
00075                                   | HSMCI_SR_RDIRE \
00076                                   | HSMCI_SR_RINDE))
00077 
00078 /** Bit mask for response errors */
00079 #define STATUS_ERRORS_RESP ((uint32_t)(HSMCI_SR_CSTOE \
00080                                        | HSMCI_SR_RTOE \
00081                                        | HSMCI_SR_RENDE \
00082                                        | HSMCI_SR_RCRCE \
00083                                        | HSMCI_SR_RDIRE \
00084                                        | HSMCI_SR_RINDE))
00085 
00086 /** Bit mask for data errors */
00087 #define STATUS_ERRORS_DATA ((uint32_t)(HSMCI_SR_UNRE \
00088                                        | HSMCI_SR_OVRE \
00089                                        | HSMCI_SR_DTOE \
00090                                        | HSMCI_SR_DCRCE))
00091 
00092 /** Max DMA size in a single transfer */
00093 #define MAX_DMA_SIZE                (XDMAC_MAX_BT_SIZE & 0xFFFFFF00)
00094 
00095 /** SD/MMC memory Single block */
00096 #define _CMDR_SDMEM_SINGLE  \
00097     (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE)
00098 /** SD/MMC memory Multi block */
00099 #define _CMDR_SDMEM_MULTI   \
00100     (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_MULTIPLE)
00101 /** SDIO byte transfer */
00102 #define _CMDR_SDIO_BYTE     \
00103     (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_BYTE)
00104 /** SDIO block transfer */
00105 #define _CMDR_SDIO_BLOCK    \
00106     (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_BLOCK)
00107 
00108 /**     @}*/
00109 /*---------------------------------------------------------------------------
00110  *         Local types
00111  *---------------------------------------------------------------------------*/
00112 
00113 /*----------------------------------------------------------------------------
00114  *         Local variable
00115  *----------------------------------------------------------------------------*/
00116 
00117 //#define MCID_DBG  0
00118 //static uint8_t bMcidDBG = 0;
00119 
00120 /** HAL for SD/MMC bus mode (MCI interface) */
00121 static sSdHalFunctions sdHal = {
00122     (fSdmmcLock)MCID_Lock,
00123     (fSdmmcRelease)MCID_Release,
00124     (fSdmmcSendCommand)MCID_SendCmd,
00125     (fSdmmcIOCtrl)MCID_IOCtrl
00126 };
00127 
00128 /*---------------------------------------------------------------------------
00129  *         Internal functions
00130  *---------------------------------------------------------------------------*/
00131 
00132 /** \addtogroup mcid_functions
00133  *@{
00134  */
00135 
00136 static void hsmci_callback(uint32_t channel, sMcid *pMcid)
00137 {
00138     channel = channel;
00139     sSdmmcCommand *pCmd = pMcid->pCmd;
00140     SCB_InvalidateDCache_by_Addr((uint32_t *)&pCmd->pData[0],
00141                                  pCmd->wBlockSize * pCmd->wNbBlocks);
00142 }
00143 
00144 /**
00145  * Enable MCI peripheral access clock
00146  */
00147 static uint8_t _PeripheralEnable(uint32_t id)
00148 {
00149     if (PMC_IsPeriphEnabled(id)) return 0;
00150 
00151     PMC_EnablePeripheral(id);
00152     return 1;
00153 }
00154 
00155 /**
00156  * HSMCI DMA R/W prepare
00157  */
00158 static uint32_t _MciDMAPrepare(sMcid *pMcid, uint8_t bRd)
00159 {
00160     sXdmad *pXdmad = pMcid->pXdmad;
00161 
00162     /* Allocate a channel */
00163     if (bRd) {
00164         pMcid->dwDmaCh = XDMAD_AllocateChannel
00165                          (pXdmad, pMcid->bID, XDMAD_TRANSFER_MEMORY);
00166         XDMAD_SetCallback(pXdmad, pMcid->dwDmaCh, (XdmadTransferCallback)hsmci_callback,
00167                           pMcid);
00168     } else {
00169         pMcid->dwDmaCh = XDMAD_AllocateChannel
00170                          (pXdmad, XDMAD_TRANSFER_MEMORY, pMcid->bID);
00171         XDMAD_SetCallback(pXdmad, pMcid->dwDmaCh, NULL, NULL);
00172     }
00173 
00174     if (pMcid->dwDmaCh == XDMAD_ALLOC_FAILED)
00175         return SDMMC_ERROR_BUSY;
00176 
00177     XDMAD_PrepareChannel(pXdmad, pMcid->dwDmaCh);
00178     return SDMMC_SUCCESS;
00179 }
00180 
00181 /**
00182  * HSMCI DMA R/W
00183  * \return 1 if DMA started.
00184  */
00185 
00186 /* Linked lists for multi transfer buffer chaining structure instance. */
00187 COMPILER_ALIGNED(32) static LinkedListDescriporView1 dmaLinkList[256];
00188 
00189 static uint32_t _MciDMA(sMcid *pMcid, uint32_t bFByte, uint8_t bRd)
00190 {
00191     Hsmci *pHw = pMcid->pMciHw;
00192     sXdmad *pXdmad = pMcid->pXdmad;
00193     sSdmmcCommand *pCmd = pMcid->pCmd;
00194     sXdmadCfg xdmadRxCfg, xdmadTxCfg;
00195     uint32_t xdmaCndc, xdmaInt;
00196     uint32_t hsmciId;
00197     uint8_t i;
00198     uint32_t totalSize = pCmd->wNbBlocks * pCmd->wBlockSize;
00199     uint32_t maxXSize;
00200     uint32_t memAddress;
00201     uint8_t  bMByte;
00202 
00203     if (pMcid->dwXfrNdx >= totalSize) return 0;
00204 
00205     /* Prepare DMA transfer */
00206     if (pCmd->wBlockSize != 1) {
00207         pMcid->dwXSize = totalSize - pMcid->dwXfrNdx;
00208         hsmciId = ID_HSMCI;
00209 
00210         if (bRd) {
00211             for (i = 0; i < pCmd->wNbBlocks; i++) {
00212                 dmaLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
00213                                          | ((i == pCmd->wNbBlocks - 1) ? 0 : XDMA_UBC_NDE_FETCH_EN)
00214                                          | XDMA_UBC_NDEN_UPDATED
00215                                          | pCmd->wBlockSize / 4;
00216                 dmaLinkList[i].mbr_sa  = (uint32_t) & (pHw->HSMCI_FIFO[i]);
00217                 dmaLinkList[i].mbr_da = (uint32_t)&pCmd->pData[i * pCmd->wBlockSize];
00218 
00219                 if (i == pCmd->wNbBlocks - 1)
00220                     dmaLinkList[i].mbr_nda = 0;
00221                 else
00222                     dmaLinkList[i].mbr_nda = (uint32_t)&dmaLinkList[ i + 1 ];
00223 
00224                 //          SCB_CleanDCache_by_Addr((uint32_t *)&dmaLinkList[i],sizeof(LinkedListDescriporView1));
00225             }
00226 
00227             xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
00228                                  | XDMAC_CC_MBSIZE_SINGLE
00229                                  | XDMAC_CC_DSYNC_PER2MEM
00230                                  | XDMAC_CC_CSIZE_CHK_1
00231                                  | XDMAC_CC_DWIDTH_WORD
00232                                  | XDMAC_CC_SIF_AHB_IF1
00233                                  | XDMAC_CC_DIF_AHB_IF1
00234                                  | XDMAC_CC_SAM_FIXED_AM
00235                                  | XDMAC_CC_DAM_INCREMENTED_AM
00236                                  | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber
00237                                                   (hsmciId, XDMAD_TRANSFER_RX));
00238             xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
00239                        | XDMAC_CNDC_NDE_DSCR_FETCH_EN
00240                        | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
00241                        | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED;
00242 
00243 
00244             if (XDMAD_ConfigureTransfer(pXdmad, pMcid->dwDmaCh,
00245                                          &xdmadRxCfg, xdmaCndc, (uint32_t)&dmaLinkList[0],
00246                                          XDMAC_CIE_LIE))
00247                 return 0;
00248 
00249             SCB_CleanDCache_by_Addr((uint32_t *)dmaLinkList, sizeof(dmaLinkList));
00250 
00251             if (XDMAD_StartTransfer(pXdmad, pMcid->dwDmaCh))
00252                 return 0;
00253 
00254             //Write
00255         } else {
00256             for (i = 0; i < pCmd->wNbBlocks; i++) {
00257                 dmaLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
00258                                          | ((i == pCmd->wNbBlocks - 1) ? 0 : XDMA_UBC_NDE_FETCH_EN)
00259                                          | XDMA_UBC_NDEN_UPDATED
00260                                          | pCmd->wBlockSize / 4;
00261                 dmaLinkList[i].mbr_sa = (uint32_t)&pCmd->pData[i * pCmd->wBlockSize];
00262                 dmaLinkList[i].mbr_da = (uint32_t) & (pHw->HSMCI_FIFO[i]);
00263 
00264                 // cache maintenance
00265                 //      SCB_CleanDCache_by_Addr((uint32_t *)&pCmd->pData[i * pCmd->wBlockSize],pCmd->wBlockSize);
00266                 if (i == pCmd->wNbBlocks - 1) dmaLinkList[i].mbr_nda = 0;
00267                 else dmaLinkList[i].mbr_nda = (uint32_t)&dmaLinkList[ i + 1 ];
00268 
00269                 //      SCB_CleanDCache_by_Addr((uint32_t *)&dmaLinkList[i],sizeof(LinkedListDescriporView1));
00270 
00271             }
00272 
00273             xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
00274                                  | XDMAC_CC_MBSIZE_SINGLE
00275                                  | XDMAC_CC_DSYNC_MEM2PER
00276                                  | XDMAC_CC_CSIZE_CHK_1
00277                                  | XDMAC_CC_DWIDTH_WORD
00278                                  | XDMAC_CC_SIF_AHB_IF1
00279                                  | XDMAC_CC_DIF_AHB_IF1
00280                                  | XDMAC_CC_SAM_INCREMENTED_AM
00281                                  | XDMAC_CC_DAM_FIXED_AM
00282                                  | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(hsmciId, XDMAD_TRANSFER_TX));
00283             xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
00284                        | XDMAC_CNDC_NDE_DSCR_FETCH_EN
00285                        | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
00286                        | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED;
00287 
00288             if (XDMAD_ConfigureTransfer(pXdmad, pMcid->dwDmaCh,
00289                                          &xdmadTxCfg, xdmaCndc, (uint32_t)&dmaLinkList[0],
00290                                          XDMAC_CIE_LIE))
00291                 return 0;
00292 
00293             SCB_CleanDCache_by_Addr((uint32_t *)&pCmd->pData[0],
00294                                     pCmd->wBlockSize * pCmd->wNbBlocks);
00295             SCB_CleanDCache_by_Addr((uint32_t *)dmaLinkList, sizeof(dmaLinkList));
00296 
00297             if (XDMAD_StartTransfer(pXdmad, pMcid->dwDmaCh))
00298                 return 0;
00299         }
00300     } else {
00301         /* Memory address and alignment */
00302         memAddress = (uint32_t)&pCmd->pData[pMcid->dwXfrNdx];
00303         bMByte = bFByte ? 1 : (((memAddress & 0x3) || (totalSize & 0x3)));
00304 
00305         /* P to M: Max size is P size */
00306         if (bRd)
00307             maxXSize = bFByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);
00308         else {
00309             /* M to P: Max size is M size */
00310             maxXSize = bMByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);
00311         }
00312 
00313         /* Update index */
00314         pMcid->dwXSize = totalSize - pMcid->dwXfrNdx;
00315 
00316         if (pMcid->dwXSize > maxXSize)
00317             pMcid->dwXSize = maxXSize;
00318 
00319         /* Prepare DMA transfer */
00320         if (bRd) {
00321             xdmadRxCfg.mbr_ubc = bFByte ? pMcid->dwXSize : toWCOUNT(pMcid->dwXSize);
00322             xdmadRxCfg.mbr_sa = (uint32_t) & (pHw->HSMCI_RDR);
00323             xdmadRxCfg.mbr_da = (uint32_t)memAddress;
00324             xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
00325                                  XDMAC_CC_MEMSET_NORMAL_MODE |
00326                                  XDMAC_CC_DSYNC_PER2MEM |
00327                                  XDMAC_CC_CSIZE_CHK_1 |
00328                                  (bFByte ? XDMAC_CC_DWIDTH_BYTE : XDMAC_CC_DWIDTH_WORD) |
00329                                  XDMAC_CC_SIF_AHB_IF1 |
00330                                  XDMAC_CC_DIF_AHB_IF1 |
00331                                  XDMAC_CC_SAM_FIXED_AM |
00332                                  XDMAC_CC_DAM_INCREMENTED_AM;
00333             xdmadRxCfg.mbr_bc = 0;
00334             xdmaInt =  (XDMAC_CIE_BIE   |
00335                         XDMAC_CIE_DIE   |
00336                         XDMAC_CIE_FIE   |
00337                         XDMAC_CIE_RBIE  |
00338                         XDMAC_CIE_WBIE  |
00339                         XDMAC_CIE_ROIE);
00340 
00341             XDMAD_ConfigureTransfer(pXdmad, pMcid->dwDmaCh, &xdmadRxCfg,
00342                                      0, 0, xdmaInt);
00343         } else {
00344             SCB_CleanDCache_by_Addr((uint32_t *)memAddress, pMcid->dwXSize);
00345             xdmadTxCfg.mbr_ubc = bFByte ? pMcid->dwXSize : toWCOUNT(pMcid->dwXSize);
00346             xdmadTxCfg.mbr_sa = (uint32_t)memAddress;
00347             xdmadTxCfg.mbr_da = (uint32_t) & (pHw->HSMCI_TDR);
00348             xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
00349                                  XDMAC_CC_MEMSET_NORMAL_MODE |
00350                                  XDMAC_CC_DSYNC_MEM2PER |
00351                                  XDMAC_CC_CSIZE_CHK_1 |
00352                                  (bFByte ? XDMAC_CC_DWIDTH_BYTE : XDMAC_CC_DWIDTH_WORD) |
00353                                  XDMAC_CC_SIF_AHB_IF1 |
00354                                  XDMAC_CC_DIF_AHB_IF1 |
00355                                  XDMAC_CC_SAM_INCREMENTED_AM |
00356                                  XDMAC_CC_DAM_FIXED_AM;
00357             xdmadTxCfg.mbr_bc = 0;
00358 
00359             xdmaInt =  (XDMAC_CIE_BIE   |
00360                         XDMAC_CIE_DIE   |
00361                         XDMAC_CIE_FIE   |
00362                         XDMAC_CIE_RBIE  |
00363                         XDMAC_CIE_WBIE  |
00364                         XDMAC_CIE_ROIE);
00365 
00366             XDMAD_ConfigureTransfer(pXdmad, pMcid->dwDmaCh, &xdmadTxCfg,
00367                                      0, 0, xdmaInt);
00368         }
00369 
00370         XDMAD_StartTransfer(pXdmad, pMcid->dwDmaCh);
00371     }
00372 
00373     return 1;
00374 }
00375 
00376 /*----------------------------------------------------------------------------
00377  *         Local functions
00378  *----------------------------------------------------------------------------*/
00379 
00380 /**
00381  * Reset MCI HW interface and disable it.
00382  * \param keepSettings Keep old register settings, including
00383  *                     _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
00384  */
00385 static void MCI_Reset(sMcid *pMci, uint8_t keepSettings)
00386 {
00387     Hsmci *pMciHw = pMci->pMciHw;
00388 
00389     assert(pMci);
00390     assert(pMci->pMciHw);
00391 
00392     HSMCI_Reset(pMciHw, keepSettings);
00393 }
00394 
00395 /**
00396  * Configure the  MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
00397  * MCK/2 and corresponds to CLKDIV = 0
00398  * \param pMci  Pointer to the low level MCI driver.
00399  * \param mciSpeed  MCI clock speed in Hz, 0 will not change current speed.
00400  * \param mck       MCK to generate MCI Clock, in Hz
00401  * \return The actual speed used, 0 for fail.
00402  */
00403 static uint32_t MCI_SetSpeed(sMcid *pMci, uint32_t mciSpeed, uint32_t mck)
00404 {
00405     Hsmci *pMciHw = pMci->pMciHw;
00406     uint32_t clkdiv;
00407     assert(pMci);
00408     assert(pMciHw);
00409 
00410     if ((mck % mciSpeed) == 0)
00411         clkdiv = mck / mciSpeed;
00412     else
00413         clkdiv = ((mck + mciSpeed) / mciSpeed);
00414 
00415     mciSpeed = mck / clkdiv;
00416 
00417     /* Modify MR */
00418     HSMCI_DivCtrl(pMciHw, clkdiv, 0x7);
00419     return (mciSpeed);
00420 }
00421 
00422 /**
00423 */
00424 static void _FinishCmd(sMcid *pMcid, uint8_t bStatus)
00425 {
00426     sSdmmcCommand *pCmd = pMcid->pCmd;
00427     sXdmad *pXdmad = pMcid->pXdmad;
00428 
00429     //uint32_t memAddress;
00430     /* Release DMA channel (if used) */
00431     if (pMcid->dwDmaCh != XDMAD_ALLOC_FAILED) {
00432         if (XDMAD_FreeChannel(pXdmad, pMcid->dwDmaCh)) {
00433             TRACE_ERROR(" Can't free channel \n\r");
00434             TRACE_DEBUG(" Channel is in %d state\n\r",
00435                         pXdmad->XdmaChannels[pMcid->dwDmaCh].state);
00436         }
00437 
00438         pMcid->dwDmaCh = XDMAD_ALLOC_FAILED;
00439     }
00440 
00441     /* Release command */
00442     pMcid->pCmd   = NULL;
00443     pMcid->bState = MCID_LOCKED;
00444     pCmd->bStatus = bStatus;
00445 
00446     /* Invoke callback */
00447     if (pCmd->fCallback)
00448         (pCmd->fCallback)(pCmd->bStatus, pCmd->pArg);
00449 }
00450 
00451 /*---------------------------------------------------------------------------
00452  *      Exported functions
00453  *---------------------------------------------------------------------------*/
00454 
00455 /**
00456  * Select MCI slot.
00457  */
00458 void MCID_SetSlot(Hsmci *pMci, uint8_t slot)
00459 
00460 {
00461     HSMCI_SetSlot(pMci, slot);
00462 }
00463 
00464 /**
00465  * Initialize MCI driver.
00466  */
00467 void MCID_Init(sMcid *pMcid,
00468                Hsmci *pMci, uint8_t bID, uint32_t dwMck,
00469                sXdmad *pXdmad,
00470                uint8_t bPolling)
00471 {
00472     uint16_t clkDiv;
00473 
00474     assert(pMcid);
00475     assert(pMci);
00476 
00477     /* Initialize driver struct */
00478     pMcid->pMciHw    = pMci;
00479     pMcid->pCmd      = NULL;
00480 
00481     pMcid->pXdmad         = pXdmad;
00482     pMcid->dwDmaCh       = XDMAD_ALLOC_FAILED;
00483     pMcid->dwXfrNdx      = 0;
00484 
00485     pMcid->dwMck     = dwMck;
00486 
00487     pMcid->bID       = bID;
00488     pMcid->bPolling  = bPolling;
00489     pMcid->bState    = MCID_IDLE;
00490 
00491     _PeripheralEnable(bID);
00492 
00493     MCI_RESET(pMci);
00494     MCI_DISABLE (pMci);
00495     HSMCI_DisableIt(pMci, 0xFFFFFFFF);
00496     HSMCI_ConfigureDataTO(pMci, HSMCI_DTOR_DTOCYC(0xFF)
00497                            | HSMCI_DTOR_DTOMUL_1048576);
00498     HSMCI_ConfigureCompletionTO(pMci , HSMCI_CSTOR_CSTOCYC(0xFF)
00499                                  | HSMCI_CSTOR_CSTOMUL_1048576);
00500     /* Set the Mode Register: 400KHz */
00501     clkDiv = (dwMck / (MCI_INITIAL_SPEED << 1)) - 1;
00502     HSMCI_ConfigureMode(pMci, (clkDiv | HSMCI_MR_PWSDIV(0x7)));
00503 
00504     HSMCI_Enable(pMci);
00505     HSMCI_Configure(pMci, HSMCI_CFG_FIFOMODE | HSMCI_CFG_FERRCTRL);
00506     /* Enable DMA */
00507     HSMCI_EnableDma(pMci, 1);
00508     //_PeripheralDisable(bID);
00509 }
00510 
00511 /**
00512  * Lock the MCI driver for slot N access
00513  */
00514 uint32_t MCID_Lock(sMcid *pMcid, uint8_t bSlot)
00515 {
00516     Hsmci *pHw = pMcid->pMciHw;
00517     uint32_t sdcr;
00518 
00519     assert(pMcid);
00520     assert(pMcid->pMciHw);
00521 
00522     if (bSlot > 0)
00523         return SDMMC_ERROR_PARAM;
00524 
00525     if (pMcid->bState >= MCID_LOCKED)
00526         return SDMMC_ERROR_LOCKED;
00527 
00528     pMcid->bState = MCID_LOCKED;
00529     sdcr = pHw->HSMCI_SDCR & ~(uint32_t)HSMCI_SDCR_SDCSEL_Msk;
00530     pHw->HSMCI_SDCR = sdcr | (bSlot << HSMCI_SDCR_SDCSEL_Pos);
00531     return SDMMC_OK;
00532 }
00533 
00534 /**
00535  * Release the driver.
00536  */
00537 uint32_t MCID_Release(sMcid *pMcid)
00538 {
00539     assert(pMcid);
00540 
00541     if (pMcid->bState >= MCID_CMD)
00542         return SDMMC_ERROR_BUSY;
00543 
00544     pMcid->bState = MCID_IDLE;
00545     return SDMMC_OK;
00546 }
00547 
00548 /**
00549  * SD/MMC command.
00550  */
00551 uint32_t MCID_SendCmd(sMcid *pMcid, void *pCommand)
00552 {
00553     Hsmci *pHw = pMcid->pMciHw;
00554     sSdmmcCommand *pCmd = pCommand;
00555     uint32_t mr, ier;
00556     uint32_t cmdr;
00557 
00558     assert(pMcid);
00559     assert(pMcid->pMciHw);
00560     assert(pCmd);
00561 
00562     //printf("cmd = %d \n\r",pCmd->bCmd);
00563     if (!MCID_IsCmdCompleted(pMcid))
00564         return SDMMC_ERROR_BUSY;
00565 
00566     pMcid->bState = MCID_CMD;
00567     pMcid->pCmd   = pCmd;
00568 
00569     //_PeripheralEnable(pMcid->bID);
00570     MCI_DISABLE(pHw);
00571     mr = HSMCI_GetMode(pHw) & (~(uint32_t)(HSMCI_MR_WRPROOF |
00572                                            HSMCI_MR_RDPROOF | HSMCI_MR_FBYTE));
00573 
00574     /* Special: PowerON Init */
00575     if (pCmd->cmdOp.wVal == SDMMC_CMD_POWERONINIT) {
00576         HSMCI_ConfigureMode(pHw, mr);
00577         ier = HSMCI_IER_XFRDONE;
00578     } else if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR) {
00579         /* Normal command: idle the bus */
00580         HSMCI_ConfigureMode(pHw, mr);
00581         ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;
00582     }
00583     /* No data transfer */
00584     else if ((pCmd->cmdOp.wVal & SDMMC_CMD_CNODATA(0xF)) == SDMMC_CMD_CNODATA(0)) {
00585         ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;
00586 
00587         /* R3 response, no CRC */
00588         if (pCmd->cmdOp.bmBits.respType == 3)
00589             ier &= ~(uint32_t)HSMCI_IER_RCRCE;
00590     } else if (pCmd->wNbBlocks == 0 || pCmd->pData == 0) {
00591         /* Data command but no following */
00592         HSMCI_ConfigureMode(pHw, mr | HSMCI_MR_WRPROOF
00593                             | HSMCI_MR_RDPROOF);
00594         HSMCI_ConfigureTransfer(pHw, pCmd->wBlockSize, pCmd->wNbBlocks);
00595         ier = HSMCI_IER_CMDRDY | STATUS_ERRORS_RESP;
00596     } else {
00597         /* Command with data */
00598         /* Setup block size */
00599         if (pCmd->cmdOp.bmBits.sendCmd)
00600             HSMCI_ConfigureTransfer(pHw, pCmd->wBlockSize, pCmd->wNbBlocks);
00601 
00602         /* Block size is 0, force byte */
00603         if (pCmd->wBlockSize == 0)
00604             pCmd->wBlockSize = 1;
00605 
00606         /* Force byte transfer */
00607         if (pCmd->wBlockSize & 0x3)
00608             mr |= HSMCI_MR_FBYTE;
00609 
00610         /* Set block size & MR */
00611         HSMCI_ConfigureMode(pHw, mr | HSMCI_MR_WRPROOF
00612                             | HSMCI_MR_RDPROOF);
00613 
00614         /* DMA write */
00615         if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_TX) {
00616             if (_MciDMAPrepare(pMcid, 0)) {
00617                 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);
00618                 return SDMMC_ERROR_BUSY;
00619             }
00620 
00621             _MciDMA(pMcid, (mr & HSMCI_MR_FBYTE), 0);
00622             ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_DATA;
00623 
00624             if (pCmd->wNbBlocks > 1) ier |= HSMCI_IER_FIFOEMPTY;
00625         } else {
00626             if (_MciDMAPrepare(pMcid, 1)) {
00627                 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);
00628                 return SDMMC_ERROR_BUSY;
00629             }
00630 
00631             _MciDMA(pMcid, (mr & HSMCI_MR_FBYTE), 1);
00632             ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_DATA;
00633 
00634             if (pCmd->wNbBlocks > 1) ier |= HSMCI_IER_FIFOEMPTY;
00635         }
00636     }
00637 
00638     MCI_ENABLE(pHw);
00639 
00640     if (pCmd->cmdOp.wVal & (SDMMC_CMD_bmPOWERON | SDMMC_CMD_bmCOMMAND)) {
00641         cmdr = pCmd->bCmd;
00642 
00643         if (pCmd->cmdOp.bmBits.powerON)
00644             cmdr |= (HSMCI_CMDR_OPDCMD | HSMCI_CMDR_SPCMD_INIT);
00645 
00646         if (pCmd->cmdOp.bmBits.odON)
00647             cmdr |= HSMCI_CMDR_OPDCMD;
00648 
00649         if (pCmd->cmdOp.bmBits.sendCmd)
00650             cmdr |= HSMCI_CMDR_MAXLAT;
00651 
00652         switch (pCmd->cmdOp.bmBits.xfrData) {
00653         case SDMMC_CMD_TX:
00654             if (pCmd->cmdOp.bmBits.ioCmd) {
00655                 cmdr |= (pCmd->wBlockSize == 1) ?
00656                         _CMDR_SDIO_BYTE :
00657                         _CMDR_SDIO_BLOCK;
00658             } else {
00659                 cmdr |= (pCmd->wNbBlocks == 1) ?
00660                         _CMDR_SDMEM_SINGLE :
00661                         _CMDR_SDMEM_MULTI;
00662             }
00663 
00664             break;
00665 
00666         case SDMMC_CMD_RX:
00667             if (pCmd->cmdOp.bmBits.ioCmd) {
00668                 cmdr |= HSMCI_CMDR_TRDIR_READ
00669                         | ((pCmd->wBlockSize == 1) ?
00670                            _CMDR_SDIO_BYTE :
00671                            _CMDR_SDIO_BLOCK);
00672             } else {
00673                 cmdr |= HSMCI_CMDR_TRDIR_READ
00674                         | ((pCmd->wNbBlocks == 1) ?
00675                            _CMDR_SDMEM_SINGLE :
00676                            _CMDR_SDMEM_MULTI);
00677             }
00678 
00679             break;
00680 
00681         case SDMMC_CMD_STOPXFR:
00682             cmdr |= HSMCI_CMDR_TRCMD_STOP_DATA;
00683             break;
00684         }
00685 
00686         switch (pCmd->cmdOp.bmBits.respType) {
00687         case 3: case 4:
00688             /* ignore CRC error */
00689             ier &= ~(uint32_t)HSMCI_IER_RCRCE;
00690 
00691         case 1: case 5: case 6: case 7:
00692             cmdr |= HSMCI_CMDR_RSPTYP_48_BIT;
00693             break;
00694 
00695         case 2:
00696             cmdr |= HSMCI_CMDR_RSPTYP_136_BIT;
00697             break;
00698 
00699         /* No response, ignore RTOE */
00700         default:
00701             ier &= ~(uint32_t)HSMCI_IER_RTOE;
00702         }
00703 
00704         pHw->HSMCI_ARGR = pCmd->dwArg;
00705         pHw->HSMCI_CMDR = cmdr;
00706     }
00707 
00708     /* Ignore CRC error for R3 & R4 */
00709     if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR)
00710         ier &= ~STATUS_ERRORS_DATA;
00711 
00712     /* Enable status flags */
00713     HSMCI_EnableIt(pHw, ier);
00714     return SDMMC_OK;
00715 }
00716 
00717 static uint32_t dwMsk;
00718 /**
00719  * Process pending events on the given MCI driver.
00720  */
00721 void MCID_Handler(sMcid *pMcid)
00722 {
00723     Hsmci *pHw = pMcid->pMciHw;
00724     sSdmmcCommand *pCmd = pMcid->pCmd;
00725     //uint32_t dwSr, dwMsk, dwMaskedSr;
00726     uint32_t dwSr, dwMaskedSr;
00727     assert(pMcid);
00728     assert(pMcid->pMciHw);
00729 
00730     /* Do nothing if no pending command */
00731     if (pCmd == NULL) {
00732         if (pMcid->bState >= MCID_CMD)
00733             pMcid->bState = MCID_LOCKED;
00734 
00735         return;
00736     }
00737 
00738     /* Read status */
00739     dwSr  = HSMCI_GetStatus(pHw);
00740     dwMsk = HSMCI_GetItMask(pHw);
00741     dwMaskedSr = dwSr & dwMsk;
00742 
00743     /* Check errors */
00744     if (dwMaskedSr & STATUS_ERRORS) {
00745         if (dwMaskedSr & HSMCI_SR_RTOE)
00746             pCmd->bStatus = SDMMC_ERROR_NORESPONSE;
00747 
00748         if (pCmd->bCmd != 12) pMcid->bState = MCID_ERROR;
00749 
00750         //pMcid->bState = MCID_ERROR;
00751     }
00752 
00753     dwMsk &= ~STATUS_ERRORS;
00754 
00755     /* Check command complete */
00756     if (dwMaskedSr & HSMCI_SR_CMDRDY) {
00757         TRACE_DEBUG("HSMCI_SR_CMDRDY \n\r");
00758         HSMCI_DisableIt(pHw, HSMCI_IDR_CMDRDY);
00759         dwMsk &= ~(uint32_t)HSMCI_IMR_CMDRDY;
00760     }
00761 
00762     /* Check if not busy */
00763     if (dwMaskedSr & HSMCI_SR_NOTBUSY) {
00764         TRACE_DEBUG("NOTBUSY ");
00765         HSMCI_DisableIt(pHw, HSMCI_IDR_NOTBUSY);
00766         dwMsk &= ~(uint32_t)HSMCI_IMR_NOTBUSY;
00767     }
00768 
00769     /* Check if TX ready */
00770     if (dwMaskedSr & HSMCI_SR_TXRDY) {
00771         TRACE_DEBUG("TXRDY ");
00772         dwMsk &= ~(uint32_t)HSMCI_IMR_TXRDY;
00773     }
00774 
00775     /* Check if FIFO empty (all data sent) */
00776     if (dwMaskedSr & HSMCI_SR_FIFOEMPTY) {
00777         /* Disable FIFO empty */
00778         HSMCI_DisableIt(pHw, HSMCI_IDR_FIFOEMPTY);
00779         dwMsk &= ~(uint32_t)HSMCI_IMR_FIFOEMPTY;
00780         TRACE_DEBUG("FIFOEMPTY %x \n\r", dwMsk);
00781     }
00782 
00783     /* Check if DMA finished */
00784     if (dwMaskedSr & HSMCI_SR_XFRDONE) {
00785         HSMCI_DisableIt(pHw, HSMCI_IDR_XFRDONE);
00786         dwMsk &= ~(uint32_t)HSMCI_IMR_XFRDONE;
00787         TRACE_DEBUG("HSMCI_SR_XFRDONE %x \n\r", dwMsk);
00788     }
00789 
00790     /* All none error mask done, complete the command */
00791     if (0 == dwMsk || pMcid->bState == MCID_ERROR) {
00792         /* Error reset */
00793         if (pMcid->bState == MCID_ERROR)
00794             MCI_Reset(pMcid, 1);
00795         else  {
00796             pCmd->bStatus = SDMMC_SUCCESS;
00797 
00798             if (pCmd->pResp) {
00799                 uint8_t bRspSize, i;
00800 
00801                 switch (pCmd->cmdOp.bmBits.respType) {
00802                 case 1: case 3: case 4: case 5: case 6: case 7:
00803                     bRspSize = 1;
00804                     break;
00805 
00806                 case 2:
00807                     bRspSize = 4;
00808                     break;
00809 
00810                 default:
00811                     bRspSize = 0;
00812                 }
00813 
00814                 for (i = 0; i < bRspSize; i ++)
00815                     pCmd->pResp[i] = HSMCI_GetResponse(pHw);
00816             }
00817         }
00818 
00819         /* Disable interrupts */
00820         HSMCI_DisableIt(pHw, HSMCI_GetItMask(pHw));
00821         /* Disable peripheral */
00822         //_PeripheralDisable(pMcid->bID);
00823         /* Command is finished */
00824         _FinishCmd(pMcid, pCmd->bStatus);
00825     }
00826 }
00827 
00828 /**
00829  * Cancel pending SD/MMC command.
00830  */
00831 uint32_t MCID_CancelCmd(sMcid *pMcid)
00832 {
00833     if (pMcid->bState == MCID_IDLE)
00834         return SDMMC_ERROR_STATE;
00835 
00836     if (pMcid->bState == MCID_CMD) {
00837         /* Cancel ... */
00838         MCI_Reset(pMcid, 1);
00839         /* Command is finished */
00840         _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);
00841     }
00842 
00843     return SDMMC_OK;
00844 }
00845 
00846 /**
00847  * Reset MCID and disable HW
00848  */
00849 void MCID_Reset(sMcid *pMcid)
00850 {
00851     Hsmci *pHw = pMcid->pMciHw;
00852 
00853     MCID_CancelCmd(pMcid);
00854 
00855     //_PeripheralEnable(pMcid->bID);
00856 
00857     /* Disable */
00858     MCI_DISABLE(pHw);
00859     /* MR reset */
00860     HSMCI_ConfigureMode(pHw, HSMCI_GetMode(pHw) & (HSMCI_MR_CLKDIV_Msk
00861                         | HSMCI_MR_PWSDIV_Msk));
00862     /* BLKR reset */
00863     HSMCI_ConfigureTransfer(pHw, 0, 0);
00864 
00865     /* Cancel ... */
00866     MCI_Reset(pMcid, 1);
00867     //_PeripheralDisable(pMcid->bID);
00868 
00869     if (pMcid->bState == MCID_CMD) {
00870         /* Command is finished */
00871         _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);
00872     }
00873 }
00874 
00875 /**
00876  * Check if the command is finished
00877  */
00878 uint32_t MCID_IsCmdCompleted(sMcid *pMcid)
00879 {
00880     sSdmmcCommand *pCmd = pMcid->pCmd;
00881 
00882     if (pMcid->bPolling)
00883         MCID_Handler(pMcid);
00884 
00885     if (pMcid->bState == MCID_CMD)
00886         return 0;
00887 
00888     if (pCmd)
00889         return 0;
00890 
00891     return 1;
00892 }
00893 
00894 /**
00895  * IO control functions
00896  */
00897 uint32_t MCID_IOCtrl(sMcid *pMcid, uint32_t bCtl, uint32_t param)
00898 {
00899     Hsmci *pMciHw = pMcid->pMciHw;
00900     assert(pMcid);
00901     assert(pMcid->pMciHw);
00902 
00903     //mciDis = _PeripheralEnable(pMcid->bID);
00904 
00905     switch (bCtl) {
00906     case SDMMC_IOCTL_BUSY_CHECK:
00907         *(uint32_t *)param = !MCID_IsCmdCompleted(pMcid);
00908         break;
00909 
00910     case SDMMC_IOCTL_POWER:
00911         return SDMMC_ERROR_NOT_SUPPORT;
00912 
00913     case SDMMC_IOCTL_RESET:
00914         MCID_Reset(pMcid);
00915         return SDMMC_SUCCESS;
00916 
00917     case SDMMC_IOCTL_CANCEL_CMD:
00918         return MCID_CancelCmd(pMcid);
00919 
00920     case SDMMC_IOCTL_SET_CLOCK:
00921         *(uint32_t *)param = MCI_SetSpeed(pMcid,
00922                                           *(uint32_t *)param,
00923                                           pMcid->dwMck);
00924         break;
00925 
00926     case SDMMC_IOCTL_SET_HSMODE:
00927         HSMCI_HsEnable(pMciHw, *(uint32_t *)param);
00928         *(uint32_t *)param = HSMCI_IsHsEnabled(pMciHw);
00929 
00930         break;
00931 
00932     case SDMMC_IOCTL_SET_BUSMODE:
00933         HSMCI_SetBusWidth(pMciHw, *(uint32_t *)param);
00934         break;
00935 
00936     case SDMMC_IOCTL_GET_BUSMODE:
00937         //*(uint32_t*)param = 8; /* Max 4-bit bus */
00938         break;
00939 
00940     case SDMMC_IOCTL_GET_HSMODE:
00941         *(uint32_t *)param = 1; /* Supported */
00942         break;
00943 
00944     default:
00945         return SDMMC_ERROR_NOT_SUPPORT;
00946     }
00947 
00948     return SDMMC_OK;
00949 }
00950 
00951 /**
00952  * Initialize the SD/MMC card driver structure for SD/MMC bus mode
00953  * \note defined in SD/MMC bus mode low level (Here uses MCI interface)
00954  */
00955 void SDD_InitializeSdmmcMode(sSdCard *pSd, void *pDrv, uint8_t bSlot)
00956 {
00957     SDD_Initialize(pSd, pDrv, bSlot, &sdHal);
00958 }
00959 
00960 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines