SAMV71 Xplained Ultra Software Package 1.4

mcid_dma.c

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