1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2014, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
32 * Implement for SD/MMC low level commands.
\r
34 * \sa \ref hsmci_module, \ref sdmmc_module
\r
37 /*----------------------------------------------------------------------------
\r
39 *----------------------------------------------------------------------------*/
\r
42 #include "libsdmmc.h"
\r
46 /*----------------------------------------------------------------------------
\r
48 *----------------------------------------------------------------------------*/
\r
49 /** \addtorgoup mcid_defines
\r
53 #define MCI_ENABLE(pMciHw) HSMCI_Enable(pMciHw)
\r
55 #define MCI_DISABLE(pMciHw) HSMCI_Disable(pMciHw)
\r
57 #define MCI_RESET(pMciHw) HSMCI_Reset(pMciHw, 0)
\r
59 /** Return halfword(16-bit) count from byte count */
\r
60 #define toHWCOUNT(byteCnt) (((byteCnt)&0x1) ? (((byteCnt)/2)+1) : ((byteCnt)/2))
\r
61 /** Return word(32-bit) count from byte count */
\r
62 #define toWCOUNT(byteCnt) (((byteCnt)&0x3) ? (((byteCnt)/4)+1) : ((byteCnt)/4))
\r
65 /** Bit mask for status register errors. */
\r
66 #define STATUS_ERRORS ((uint32_t)(HSMCI_SR_UNRE \
\r
68 | HSMCI_SR_ACKRCVE \
\r
78 /** Bit mask for response errors */
\r
79 #define STATUS_ERRORS_RESP ((uint32_t)(HSMCI_SR_CSTOE \
\r
86 /** Bit mask for data errors */
\r
87 #define STATUS_ERRORS_DATA ((uint32_t)(HSMCI_SR_UNRE \
\r
92 /** Max DMA size in a single transfer */
\r
93 #define MAX_DMA_SIZE (XDMAC_MAX_BT_SIZE & 0xFFFFFF00)
\r
95 /** SD/MMC memory Single block */
\r
96 #define _CMDR_SDMEM_SINGLE \
\r
97 (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_SINGLE)
\r
98 /** SD/MMC memory Multi block */
\r
99 #define _CMDR_SDMEM_MULTI \
\r
100 (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_MULTIPLE)
\r
101 /** SDIO byte transfer */
\r
102 #define _CMDR_SDIO_BYTE \
\r
103 (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_BYTE)
\r
104 /** SDIO block transfer */
\r
105 #define _CMDR_SDIO_BLOCK \
\r
106 (HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRTYP_BLOCK)
\r
109 /*---------------------------------------------------------------------------
\r
111 *---------------------------------------------------------------------------*/
\r
113 /*----------------------------------------------------------------------------
\r
115 *----------------------------------------------------------------------------*/
\r
117 //#define MCID_DBG 0
\r
118 //static uint8_t bMcidDBG = 0;
\r
120 /** HAL for SD/MMC bus mode (MCI interface) */
\r
121 static sSdHalFunctions sdHal = {
\r
122 (fSdmmcLock)MCID_Lock,
\r
123 (fSdmmcRelease)MCID_Release,
\r
124 (fSdmmcSendCommand)MCID_SendCmd,
\r
125 (fSdmmcIOCtrl)MCID_IOCtrl
\r
128 /*---------------------------------------------------------------------------
\r
129 * Internal functions
\r
130 *---------------------------------------------------------------------------*/
\r
132 /** \addtogroup mcid_functions
\r
137 * Enable MCI peripheral access clock
\r
139 static uint8_t _PeripheralEnable(uint32_t id)
\r
141 if (PMC_IsPeriphEnabled(id)) return 0;
\r
142 PMC_EnablePeripheral(id);
\r
146 static void MciDma_Cb(uint32_t channel, sMcid* pArg)
\r
149 pArg->bOpStatus = 0;
\r
151 XDMAD_FreeChannel(pArg->pXdmad, channel);
\r
155 * HSMCI DMA R/W prepare
\r
157 static uint32_t _MciDMAPrepare(sMcid *pMcid, uint8_t bRd)
\r
159 sXdmad *pXdmad = pMcid->pXdmad;
\r
160 /* Allocate a channel */
\r
162 while(pMcid->bOpStatus);
\r
163 pMcid->bOpStatus = 1;
\r
164 pMcid->dwDmaCh = XDMAD_AllocateChannel(pXdmad, pMcid->bID, XDMAD_TRANSFER_MEMORY);
\r
167 while(pMcid->bOpStatus);
\r
168 pMcid->bOpStatus = 2;
\r
169 pMcid->dwDmaCh = XDMAD_AllocateChannel(pXdmad, XDMAD_TRANSFER_MEMORY, pMcid->bID);
\r
171 if (pMcid->dwDmaCh == XDMAD_ALLOC_FAILED)
\r
173 return SDMMC_ERROR_BUSY;
\r
175 XDMAD_SetCallback(pXdmad, pMcid->dwDmaCh, (XdmadTransferCallback)MciDma_Cb, pMcid);
\r
176 // XDMAD_SetCallback(pXdmad, pMcid->dwDmaCh, 0,0);
\r
177 XDMAD_PrepareChannel( pXdmad, pMcid->dwDmaCh );
\r
178 return SDMMC_SUCCESS;
\r
183 * \return 1 if DMA started.
\r
186 /* Linked lists for multi transfer buffer chaining structure instance. */
\r
187 #if defined ( __ICCARM__ ) /* IAR Ewarm */
\r
188 #pragma location = "region_dma_nocache"
\r
189 #elif defined ( __GNUC__ ) /* GCC CS3 */
\r
190 __attribute__((__section__(".region_dma_nocache")))
\r
192 static LinkedListDescriporView1 dmaLinkList[256];
\r
194 static uint32_t _MciDMA(sMcid *pMcid, uint32_t bFByte, uint8_t bRd)
\r
196 Hsmci *pHw = pMcid->pMciHw;
\r
197 sXdmad *pXdmad = pMcid->pXdmad;
\r
198 sSdmmcCommand *pCmd = pMcid->pCmd;
\r
199 sXdmadCfg xdmadRxCfg,xdmadTxCfg;
\r
203 uint32_t totalSize = pCmd->wNbBlocks * pCmd->wBlockSize;
\r
205 uint32_t memAddress;
\r
208 if (pMcid->dwXfrNdx >= totalSize) return 0;
\r
209 /* Prepare DMA transfer */
\r
210 if(pCmd->wBlockSize != 1){
\r
211 pMcid->dwXSize = totalSize - pMcid->dwXfrNdx;
\r
212 hsmciId = ID_HSMCI;
\r
214 //printf("_MciDMA read %d,%d \n\r",pCmd->wBlockSize, pCmd->bCmd );
\r
215 for ( i = 0; i < pCmd->wNbBlocks; i++){
\r
216 dmaLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
\r
217 | (( i == pCmd->wNbBlocks - 1) ? 0: XDMA_UBC_NDE_FETCH_EN)
\r
218 | XDMA_UBC_NDEN_UPDATED
\r
219 | pCmd->wBlockSize /4 ;
\r
220 dmaLinkList[i].mbr_sa = (uint32_t)&(pHw->HSMCI_FIFO[i]);
\r
221 dmaLinkList[i].mbr_da = (uint32_t)&pCmd->pData[i * pCmd->wBlockSize];
\r
222 if ( i == pCmd->wNbBlocks - 1)
\r
223 dmaLinkList[i].mbr_nda = 0;
\r
225 dmaLinkList[i].mbr_nda = (uint32_t)&dmaLinkList[ i + 1 ];
\r
228 xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
\r
229 | XDMAC_CC_MBSIZE_SINGLE
\r
230 | XDMAC_CC_DSYNC_PER2MEM
\r
231 | XDMAC_CC_CSIZE_CHK_1
\r
232 | XDMAC_CC_DWIDTH_WORD
\r
233 | XDMAC_CC_SIF_AHB_IF1
\r
234 | XDMAC_CC_DIF_AHB_IF0
\r
235 | XDMAC_CC_SAM_FIXED_AM
\r
236 | XDMAC_CC_DAM_INCREMENTED_AM
\r
237 | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(hsmciId, XDMAD_TRANSFER_RX ));
\r
238 xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
\r
239 | XDMAC_CNDC_NDE_DSCR_FETCH_EN
\r
240 | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
\r
241 | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ;
\r
242 if (XDMAD_ConfigureTransfer( pXdmad, pMcid->dwDmaCh, &xdmadRxCfg, xdmaCndc, (uint32_t)&dmaLinkList[0])) {
\r
245 if (XDMAD_StartTransfer(pXdmad,pMcid->dwDmaCh)) {
\r
250 //printf("_MciDMA write %d,%d \n\r",pCmd->wBlockSize, pCmd->bCmd );
\r
251 for ( i = 0; i < pCmd->wNbBlocks; i++){
\r
252 dmaLinkList[i].mbr_ubc = XDMA_UBC_NVIEW_NDV1
\r
253 |(( i == pCmd->wNbBlocks - 1) ? 0: XDMA_UBC_NDE_FETCH_EN)
\r
254 | XDMA_UBC_NDEN_UPDATED
\r
255 | pCmd->wBlockSize /4 ;
\r
256 dmaLinkList[i].mbr_sa = (uint32_t)&pCmd->pData[i * pCmd->wBlockSize];
\r
257 dmaLinkList[i].mbr_da = (uint32_t)&(pHw->HSMCI_FIFO[i]);
\r
258 if ( i == pCmd->wNbBlocks - 1) dmaLinkList[i].mbr_nda = 0;
\r
259 else dmaLinkList[i].mbr_nda = (uint32_t)&dmaLinkList[ i + 1 ];
\r
262 xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN
\r
263 | XDMAC_CC_MBSIZE_SINGLE
\r
264 | XDMAC_CC_DSYNC_MEM2PER
\r
265 | XDMAC_CC_CSIZE_CHK_1
\r
266 | XDMAC_CC_DWIDTH_WORD
\r
267 | XDMAC_CC_SIF_AHB_IF0
\r
268 | XDMAC_CC_DIF_AHB_IF1
\r
269 | XDMAC_CC_SAM_INCREMENTED_AM
\r
270 | XDMAC_CC_DAM_FIXED_AM
\r
271 | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(hsmciId, XDMAD_TRANSFER_TX ));
\r
272 xdmaCndc = XDMAC_CNDC_NDVIEW_NDV1
\r
273 | XDMAC_CNDC_NDE_DSCR_FETCH_EN
\r
274 | XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED
\r
275 | XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED ;
\r
277 if(XDMAD_ConfigureTransfer( pXdmad, pMcid->dwDmaCh, &xdmadTxCfg, xdmaCndc, (uint32_t)&dmaLinkList[0])){
\r
280 if (XDMAD_StartTransfer(pXdmad,pMcid->dwDmaCh)) {
\r
285 /* Memory address and alignment */
\r
286 memAddress = (uint32_t)&pCmd->pData[pMcid->dwXfrNdx];
\r
287 bMByte = bFByte ? 1 : (((memAddress & 0x3) || (totalSize & 0x3)));
\r
288 /* P to M: Max size is P size */
\r
291 maxXSize = bFByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);
\r
293 /* M to P: Max size is M size */
\r
296 maxXSize = bMByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);
\r
299 pMcid->dwXSize = totalSize - pMcid->dwXfrNdx;
\r
300 if (pMcid->dwXSize > maxXSize)
\r
302 pMcid->dwXSize = maxXSize;
\r
304 /* Prepare DMA transfer */
\r
307 xdmadRxCfg.mbr_ubc = bFByte ? pMcid->dwXSize : toWCOUNT(pMcid->dwXSize);
\r
308 xdmadRxCfg.mbr_sa = (uint32_t)&(pHw->HSMCI_RDR);
\r
309 xdmadRxCfg.mbr_da = (uint32_t)memAddress;
\r
310 xdmadRxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
\r
311 XDMAC_CC_MEMSET_NORMAL_MODE |
\r
312 XDMAC_CC_DSYNC_PER2MEM|
\r
313 XDMAC_CC_CSIZE_CHK_1 |
\r
314 (bFByte ? XDMAC_CC_DWIDTH_BYTE : XDMAC_CC_DWIDTH_WORD) |
\r
315 XDMAC_CC_SIF_AHB_IF1 |
\r
316 XDMAC_CC_DIF_AHB_IF0 |
\r
317 XDMAC_CC_SAM_FIXED_AM |
\r
318 XDMAC_CC_DAM_INCREMENTED_AM;
\r
319 xdmadRxCfg.mbr_bc = 0;
\r
320 XDMAD_ConfigureTransfer( pXdmad, pMcid->dwDmaCh, &xdmadRxCfg, 0, 0);
\r
325 xdmadTxCfg.mbr_ubc = toWCOUNT(pMcid->dwXSize);
\r
326 xdmadTxCfg.mbr_sa = (uint32_t)memAddress;
\r
327 xdmadTxCfg.mbr_da = (uint32_t)&(pHw->HSMCI_TDR);
\r
328 xdmadTxCfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
\r
329 XDMAC_CC_MEMSET_NORMAL_MODE |
\r
330 XDMAC_CC_DSYNC_MEM2PER |
\r
331 XDMAC_CC_CSIZE_CHK_1 |
\r
332 (bFByte ? XDMAC_CC_DWIDTH_BYTE : XDMAC_CC_DWIDTH_WORD) |
\r
333 XDMAC_CC_SIF_AHB_IF0 |
\r
334 XDMAC_CC_DIF_AHB_IF1 |
\r
335 XDMAC_CC_SAM_INCREMENTED_AM |
\r
336 XDMAC_CC_DAM_FIXED_AM;
\r
337 xdmadTxCfg.mbr_bc = 0;
\r
338 XDMAD_ConfigureTransfer( pXdmad, pMcid->dwDmaCh, &xdmadTxCfg, 0, 0);
\r
340 XDMAD_StartTransfer(pXdmad, pMcid->dwDmaCh);
\r
346 /*----------------------------------------------------------------------------
\r
348 *----------------------------------------------------------------------------*/
\r
351 * Reset MCI HW interface and disable it.
\r
352 * \param keepSettings Keep old register settings, including
\r
353 * _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
\r
355 static void MCI_Reset(sMcid *pMci, uint8_t keepSettings)
\r
357 Hsmci *pMciHw = pMci->pMciHw;
\r
360 assert(pMci->pMciHw);
\r
362 HSMCI_Reset( pMciHw, keepSettings );
\r
366 * Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
\r
367 * MCK/2 and corresponds to CLKDIV = 0
\r
368 * \param pMci Pointer to the low level MCI driver.
\r
369 * \param mciSpeed MCI clock speed in Hz, 0 will not change current speed.
\r
370 * \param mck MCK to generate MCI Clock, in Hz
\r
371 * \return The actual speed used, 0 for fail.
\r
373 static uint32_t MCI_SetSpeed( sMcid* pMci, uint32_t mciSpeed, uint32_t mck )
\r
375 Hsmci *pMciHw = pMci->pMciHw;
\r
380 if((mck % mciSpeed) == 0)
\r
382 clkdiv = mck /mciSpeed;
\r
386 clkdiv = ((mck + mciSpeed)/mciSpeed);
\r
388 mciSpeed = mck / clkdiv;
\r
391 HSMCI_DivCtrl( pMciHw, clkdiv, 0x7);
\r
397 static void _FinishCmd( sMcid* pMcid, uint8_t bStatus )
\r
399 sSdmmcCommand *pCmd = pMcid->pCmd;
\r
400 sXdmad *pXdmad = pMcid->pXdmad;
\r
401 //uint32_t memAddress;
\r
402 /* Release DMA channel (if used) */
\r
403 if (pMcid->dwDmaCh != XDMAD_ALLOC_FAILED)
\r
405 if (XDMAD_FreeChannel(pXdmad, pMcid->dwDmaCh))
\r
406 TRACE_DEBUG("-E- Can't free channel \n\r");
\r
407 pMcid->dwDmaCh = XDMAD_ALLOC_FAILED;
\r
409 /* Release command */
\r
410 pMcid->pCmd = NULL;
\r
411 pMcid->bState = MCID_LOCKED;
\r
412 pCmd->bStatus = bStatus;
\r
413 /* Invoke callback */
\r
414 if (pCmd->fCallback)
\r
416 (pCmd->fCallback)(pCmd->bStatus, pCmd->pArg);
\r
420 /*---------------------------------------------------------------------------
\r
421 * Exported functions
\r
422 *---------------------------------------------------------------------------*/
\r
427 void MCID_SetSlot(Hsmci *pMci, uint8_t slot)
\r
430 HSMCI_SetSlot(pMci, slot);
\r
434 * Initialize MCI driver.
\r
436 void MCID_Init(sMcid *pMcid,
\r
437 Hsmci *pMci, uint8_t bID, uint32_t dwMck,
\r
446 /* Initialize driver struct */
\r
447 pMcid->pMciHw = pMci;
\r
448 pMcid->pCmd = NULL;
\r
450 pMcid->pXdmad = pXdmad;
\r
451 pMcid->dwDmaCh = XDMAD_ALLOC_FAILED;
\r
452 pMcid->dwXfrNdx = 0;
\r
454 pMcid->dwMck = dwMck;
\r
457 pMcid->bPolling = bPolling;
\r
458 pMcid->bState = MCID_IDLE;
\r
460 pMcid->bOpStatus = 0;
\r
462 _PeripheralEnable( bID );
\r
465 MCI_DISABLE ( pMci );
\r
466 HSMCI_DisableIt( pMci, 0xFFFFFFFF );
\r
467 HSMCI_ConfigureDataTO( pMci, HSMCI_DTOR_DTOCYC(0xFF)
\r
468 |HSMCI_DTOR_DTOMUL_1048576 );
\r
469 HSMCI_ConfigureCompletionTO( pMci , HSMCI_CSTOR_CSTOCYC(0xFF)
\r
470 |HSMCI_CSTOR_CSTOMUL_1048576 );
\r
471 /* Set the Mode Register: 400KHz */
\r
472 clkDiv = (dwMck / (MCI_INITIAL_SPEED << 1)) - 1;
\r
473 HSMCI_ConfigureMode( pMci, (clkDiv | HSMCI_MR_PWSDIV(0x7)) );
\r
475 HSMCI_Enable( pMci );
\r
476 HSMCI_Configure( pMci, HSMCI_CFG_FIFOMODE | HSMCI_CFG_FERRCTRL );
\r
478 HSMCI_EnableDma( pMci, 1 );
\r
479 //_PeripheralDisable( bID );
\r
483 * Lock the MCI driver for slot N access
\r
485 uint32_t MCID_Lock(sMcid *pMcid, uint8_t bSlot)
\r
487 Hsmci *pHw = pMcid->pMciHw;
\r
491 assert(pMcid->pMciHw);
\r
495 return SDMMC_ERROR_PARAM;
\r
497 if (pMcid->bState >= MCID_LOCKED)
\r
499 return SDMMC_ERROR_LOCKED;
\r
501 pMcid->bState = MCID_LOCKED;
\r
502 sdcr = pHw->HSMCI_SDCR & ~(uint32_t)HSMCI_SDCR_SDCSEL_Msk;
\r
503 pHw->HSMCI_SDCR = sdcr | (bSlot << HSMCI_SDCR_SDCSEL_Pos);
\r
508 * Release the driver.
\r
510 uint32_t MCID_Release(sMcid *pMcid)
\r
514 if (pMcid->bState >= MCID_CMD)
\r
516 return SDMMC_ERROR_BUSY;
\r
518 pMcid->bState = MCID_IDLE;
\r
525 uint32_t MCID_SendCmd(sMcid *pMcid, void *pCommand)
\r
527 Hsmci *pHw = pMcid->pMciHw;
\r
528 sSdmmcCommand *pCmd = pCommand;
\r
533 assert(pMcid->pMciHw);
\r
535 //printf("cmd = %d \n\r",pCmd->bCmd);
\r
536 if (!MCID_IsCmdCompleted(pMcid))
\r
538 return SDMMC_ERROR_BUSY;
\r
540 pMcid->bState = MCID_CMD;
\r
541 pMcid->pCmd = pCmd;
\r
543 //_PeripheralEnable(pMcid->bID);
\r
545 mr = HSMCI_GetMode(pHw) & (~(uint32_t)(HSMCI_MR_WRPROOF | HSMCI_MR_RDPROOF |HSMCI_MR_FBYTE));
\r
546 /* Special: PowerON Init */
\r
547 if (pCmd->cmdOp.wVal == SDMMC_CMD_POWERONINIT){
\r
548 HSMCI_ConfigureMode(pHw, mr);
\r
549 ier = HSMCI_IER_XFRDONE;
\r
551 /* Normal command: idle the bus */
\r
552 else if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR)
\r
554 HSMCI_ConfigureMode(pHw, mr);
\r
555 ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;
\r
557 /* No data transfer */
\r
558 else if ((pCmd->cmdOp.wVal & SDMMC_CMD_CNODATA(0xF)) == SDMMC_CMD_CNODATA(0))
\r
560 ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;
\r
561 /* R3 response, no CRC */
\r
562 if (pCmd->cmdOp.bmBits.respType == 3)
\r
564 ier &= ~(uint32_t)HSMCI_IER_RCRCE;
\r
567 /* Data command but no following */
\r
568 else if (pCmd->wNbBlocks == 0 || pCmd->pData == 0)
\r
570 HSMCI_ConfigureMode(pHw, mr | HSMCI_MR_WRPROOF
\r
571 | HSMCI_MR_RDPROOF);
\r
572 HSMCI_ConfigureTransfer(pHw, pCmd->wBlockSize, pCmd->wNbBlocks);
\r
573 ier = HSMCI_IER_CMDRDY | STATUS_ERRORS_RESP;
\r
575 /* Command with data */
\r
578 /* Setup block size */
\r
579 if (pCmd->cmdOp.bmBits.sendCmd)
\r
581 HSMCI_ConfigureTransfer(pHw, pCmd->wBlockSize, pCmd->wNbBlocks);
\r
583 /* Block size is 0, force byte */
\r
584 if (pCmd->wBlockSize == 0)
\r
585 pCmd->wBlockSize = 1;
\r
587 /* Force byte transfer */
\r
588 if (pCmd->wBlockSize & 0x3)
\r
590 mr |= HSMCI_MR_FBYTE;
\r
592 /* Set block size & MR */
\r
593 HSMCI_ConfigureMode(pHw, mr | HSMCI_MR_WRPROOF
\r
595 | (pCmd->wBlockSize << 16));
\r
598 if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_TX)
\r
600 if (_MciDMAPrepare(pMcid, 0))
\r
602 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);
\r
603 return SDMMC_ERROR_BUSY;
\r
605 _MciDMA(pMcid, (mr & HSMCI_MR_FBYTE),0);
\r
606 ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_DATA;
\r
607 if( pCmd->wNbBlocks > 1 ) ier |= HSMCI_IER_FIFOEMPTY;
\r
611 if (_MciDMAPrepare(pMcid, 1))
\r
613 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);
\r
614 return SDMMC_ERROR_BUSY;
\r
616 _MciDMA(pMcid, (mr & HSMCI_MR_FBYTE),1);
\r
617 ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_DATA;
\r
618 if( pCmd->wNbBlocks > 1 ) ier |= HSMCI_IER_FIFOEMPTY;
\r
622 if (pCmd->cmdOp.wVal & (SDMMC_CMD_bmPOWERON | SDMMC_CMD_bmCOMMAND))
\r
626 if (pCmd->cmdOp.bmBits.powerON)
\r
628 cmdr |= (HSMCI_CMDR_OPDCMD | HSMCI_CMDR_SPCMD_INIT);
\r
630 if (pCmd->cmdOp.bmBits.odON)
\r
632 cmdr |= HSMCI_CMDR_OPDCMD;
\r
634 if (pCmd->cmdOp.bmBits.sendCmd)
\r
636 cmdr |= HSMCI_CMDR_MAXLAT;
\r
638 switch(pCmd->cmdOp.bmBits.xfrData)
\r
641 if (pCmd->cmdOp.bmBits.ioCmd)
\r
643 cmdr |= (pCmd->wBlockSize == 1) ?
\r
649 cmdr |= (pCmd->wNbBlocks == 1) ?
\r
650 _CMDR_SDMEM_SINGLE :
\r
656 if (pCmd->cmdOp.bmBits.ioCmd)
\r
658 cmdr |= HSMCI_CMDR_TRDIR_READ
\r
659 |((pCmd->wBlockSize == 1) ?
\r
666 cmdr |= HSMCI_CMDR_TRDIR_READ
\r
667 |((pCmd->wNbBlocks == 1) ?
\r
668 _CMDR_SDMEM_SINGLE :
\r
674 case SDMMC_CMD_STOPXFR:
\r
675 cmdr |= HSMCI_CMDR_TRCMD_STOP_DATA;
\r
679 switch(pCmd->cmdOp.bmBits.respType)
\r
682 /* ignore CRC error */
\r
683 ier &= ~(uint32_t)HSMCI_IER_RCRCE;
\r
684 case 1: case 5: case 6: case 7:
\r
685 cmdr |= HSMCI_CMDR_RSPTYP_48_BIT;
\r
688 cmdr |= HSMCI_CMDR_RSPTYP_136_BIT;
\r
690 /* No response, ignore RTOE */
\r
692 ier &= ~(uint32_t)HSMCI_IER_RTOE;
\r
695 pHw->HSMCI_ARGR = pCmd->dwArg;
\r
696 pHw->HSMCI_CMDR = cmdr;
\r
699 /* Ignore CRC error for R3 & R4 */
\r
700 if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR)
\r
702 ier &= ~STATUS_ERRORS_DATA;
\r
705 /* Enable status flags */
\r
706 HSMCI_EnableIt(pHw, ier);
\r
710 static uint32_t dwMsk;
\r
712 * Process pending events on the given MCI driver.
\r
714 void MCID_Handler(sMcid *pMcid)
\r
716 Hsmci *pHw = pMcid->pMciHw;
\r
717 sSdmmcCommand *pCmd = pMcid->pCmd;
\r
718 //uint32_t dwSr, dwMsk, dwMaskedSr;
\r
719 uint32_t dwSr, dwMaskedSr;
\r
721 assert(pMcid->pMciHw);
\r
723 /* Do nothing if no pending command */
\r
726 if (pMcid->bState >= MCID_CMD)
\r
728 pMcid->bState = MCID_LOCKED;
\r
734 dwSr = HSMCI_GetStatus(pHw);
\r
735 dwMsk = HSMCI_GetItMask(pHw);
\r
736 dwMaskedSr = dwSr & dwMsk;
\r
738 if (dwMaskedSr & STATUS_ERRORS)
\r
740 if (dwMaskedSr & HSMCI_SR_RTOE)
\r
742 pCmd->bStatus = SDMMC_ERROR_NORESPONSE;
\r
745 if (pCmd->bCmd != 12) pMcid->bState = MCID_ERROR;
\r
746 //pMcid->bState = MCID_ERROR;
\r
748 dwMsk &= ~STATUS_ERRORS;
\r
750 /* Check command complete */
\r
751 if (dwMaskedSr & HSMCI_SR_CMDRDY)
\r
753 //printf("HSMCI_SR_CMDRDY \n\r");
\r
754 HSMCI_DisableIt(pHw, HSMCI_IDR_CMDRDY);
\r
755 dwMsk &= ~(uint32_t)HSMCI_IMR_CMDRDY;
\r
758 /* Check if not busy */
\r
759 if (dwMaskedSr & HSMCI_SR_NOTBUSY)
\r
761 //printf("NOTBUSY ");
\r
762 HSMCI_DisableIt(pHw, HSMCI_IDR_NOTBUSY);
\r
763 dwMsk &= ~(uint32_t)HSMCI_IMR_NOTBUSY;
\r
765 /* Check if TX ready */
\r
766 if (dwMaskedSr & HSMCI_SR_TXRDY)
\r
768 // printf("TXRDY ");
\r
769 dwMsk &= ~(uint32_t)HSMCI_IMR_TXRDY;
\r
771 /* Check if FIFO empty (all data sent) */
\r
772 if (dwMaskedSr & HSMCI_SR_FIFOEMPTY)
\r
775 /* Disable FIFO empty */
\r
776 HSMCI_DisableIt(pHw, HSMCI_IDR_FIFOEMPTY);
\r
777 dwMsk &= ~(uint32_t)HSMCI_IMR_FIFOEMPTY;
\r
778 //printf("FIFOEMPTY %x \n\r",dwMsk);
\r
781 /* Check if DMA finished */
\r
782 if (dwMaskedSr & HSMCI_SR_XFRDONE)
\r
785 HSMCI_DisableIt(pHw, HSMCI_IDR_XFRDONE);
\r
786 dwMsk &= ~(uint32_t)HSMCI_IMR_XFRDONE;
\r
787 //printf("HSMCI_SR_XFRDONE %x \n\r",dwMsk);
\r
790 /* All none error mask done, complete the command */
\r
791 if (0 == dwMsk || pMcid->bState == MCID_ERROR)
\r
794 if (pMcid->bState == MCID_ERROR)
\r
796 MCI_Reset(pMcid, 1);
\r
800 pCmd->bStatus = SDMMC_SUCCESS;
\r
804 uint8_t bRspSize, i;
\r
805 switch(pCmd->cmdOp.bmBits.respType)
\r
807 case 1: case 3: case 4: case 5: case 6: case 7:
\r
818 for (i = 0; i < bRspSize; i ++)
\r
820 pCmd->pResp[i] = HSMCI_GetResponse(pHw);
\r
824 /* Disable interrupts */
\r
825 HSMCI_DisableIt(pHw, HSMCI_GetItMask(pHw));
\r
826 /* Disable peripheral */
\r
827 //_PeripheralDisable(pMcid->bID);
\r
828 /* Command is finished */
\r
830 _FinishCmd(pMcid, pCmd->bStatus);
\r
835 * Cancel pending SD/MMC command.
\r
837 uint32_t MCID_CancelCmd(sMcid *pMcid)
\r
839 if (pMcid->bState == MCID_IDLE)
\r
841 return SDMMC_ERROR_STATE;
\r
843 if (pMcid->bState == MCID_CMD)
\r
846 MCI_Reset(pMcid, 1);
\r
847 /* Command is finished */
\r
848 _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);
\r
854 * Reset MCID and disable HW
\r
856 void MCID_Reset(sMcid * pMcid)
\r
858 Hsmci *pHw = pMcid->pMciHw;
\r
860 MCID_CancelCmd(pMcid);
\r
862 //_PeripheralEnable(pMcid->bID);
\r
867 HSMCI_ConfigureMode(pHw, HSMCI_GetMode(pHw) & (HSMCI_MR_CLKDIV_Msk
\r
868 | HSMCI_MR_PWSDIV_Msk));
\r
870 HSMCI_ConfigureTransfer(pHw, 0, 0);
\r
873 MCI_Reset(pMcid, 1);
\r
874 //_PeripheralDisable(pMcid->bID);
\r
876 if (pMcid->bState == MCID_CMD)
\r
878 /* Command is finished */
\r
879 _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);
\r
884 * Check if the command is finished
\r
886 uint32_t MCID_IsCmdCompleted(sMcid *pMcid)
\r
888 sSdmmcCommand *pCmd = pMcid->pCmd;
\r
890 if (pMcid->bPolling)
\r
892 MCID_Handler(pMcid);
\r
894 if (pMcid->bState == MCID_CMD)
\r
906 * IO control functions
\r
908 uint32_t MCID_IOCtrl(sMcid *pMcid, uint32_t bCtl, uint32_t param)
\r
910 Hsmci *pMciHw = pMcid->pMciHw;
\r
912 assert(pMcid->pMciHw);
\r
914 //mciDis = _PeripheralEnable(pMcid->bID);
\r
918 case SDMMC_IOCTL_BUSY_CHECK:
\r
919 *(uint32_t*)param = !MCID_IsCmdCompleted(pMcid);
\r
922 case SDMMC_IOCTL_POWER:
\r
923 return SDMMC_ERROR_NOT_SUPPORT;
\r
925 case SDMMC_IOCTL_RESET:
\r
927 return SDMMC_SUCCESS;
\r
929 case SDMMC_IOCTL_CANCEL_CMD:
\r
930 return MCID_CancelCmd(pMcid);
\r
932 case SDMMC_IOCTL_SET_CLOCK:
\r
933 *(uint32_t*)param = MCI_SetSpeed(pMcid,
\r
938 case SDMMC_IOCTL_SET_HSMODE:
\r
939 HSMCI_HsEnable( pMciHw, *(uint32_t*)param );
\r
940 *(uint32_t*)param = HSMCI_IsHsEnabled( pMciHw );
\r
944 case SDMMC_IOCTL_SET_BUSMODE:
\r
945 HSMCI_SetBusWidth( pMciHw, *(uint32_t*)param );
\r
948 case SDMMC_IOCTL_GET_BUSMODE:
\r
949 //*(uint32_t*)param = 8; /* Max 4-bit bus */
\r
952 case SDMMC_IOCTL_GET_HSMODE:
\r
953 *(uint32_t*)param = 1; /* Supported */
\r
957 return SDMMC_ERROR_NOT_SUPPORT;
\r
964 * Initialize the SD/MMC card driver struct for SD/MMC bus mode
\r
965 * \note defined in SD/MMC bus mode low level (Here uses MCI interface)
\r
967 void SDD_InitializeSdmmcMode(sSdCard * pSd,void * pDrv,uint8_t bSlot)
\r
969 SDD_Initialize(pSd, pDrv, bSlot, &sdHal);
\r