]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libchip_samv7/source/mcid_dma.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libchip_samv7 / source / mcid_dma.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License \r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2014, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\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
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\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
16  *\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
28  */\r
29 \r
30 /** \file\r
31  *\r
32  *  Implement for SD/MMC low level commands.\r
33  *\r
34  *  \sa \ref hsmci_module, \ref sdmmc_module\r
35  */\r
36 \r
37 /*----------------------------------------------------------------------------\r
38  *         Headers\r
39  *----------------------------------------------------------------------------*/\r
40 \r
41 #include "board.h"\r
42 #include "libsdmmc.h"\r
43 \r
44 #include <assert.h>\r
45 \r
46 /*----------------------------------------------------------------------------\r
47  *         Local constants\r
48  *----------------------------------------------------------------------------*/\r
49 /** \addtorgoup mcid_defines\r
50  *      @{*/\r
51 \r
52 /** Enable MCI */\r
53 #define MCI_ENABLE(pMciHw)     HSMCI_Enable(pMciHw)\r
54 /** Disable MCI */\r
55 #define MCI_DISABLE(pMciHw)    HSMCI_Disable(pMciHw)\r
56 /** Reset MCI */\r
57 #define MCI_RESET(pMciHw)      HSMCI_Reset(pMciHw, 0)\r
58 \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
63 \r
64 \r
65 /** Bit mask for status register errors. */\r
66 #define STATUS_ERRORS ((uint32_t)(HSMCI_SR_UNRE  \\r
67             | HSMCI_SR_OVRE \\r
68             | HSMCI_SR_ACKRCVE \\r
69             | HSMCI_SR_CSTOE \\r
70             | HSMCI_SR_DTOE \\r
71             | HSMCI_SR_DCRCE \\r
72             | HSMCI_SR_RTOE \\r
73             | HSMCI_SR_RENDE \\r
74             | HSMCI_SR_RCRCE \\r
75             | HSMCI_SR_RDIRE \\r
76             | HSMCI_SR_RINDE))\r
77 \r
78 /** Bit mask for response errors */\r
79 #define STATUS_ERRORS_RESP ((uint32_t)(HSMCI_SR_CSTOE \\r
80             | HSMCI_SR_RTOE \\r
81             | HSMCI_SR_RENDE \\r
82             | HSMCI_SR_RCRCE \\r
83             | HSMCI_SR_RDIRE \\r
84             | HSMCI_SR_RINDE))\r
85 \r
86 /** Bit mask for data errors */\r
87 #define STATUS_ERRORS_DATA ((uint32_t)(HSMCI_SR_UNRE \\r
88             | HSMCI_SR_OVRE \\r
89             | HSMCI_SR_DTOE \\r
90             | HSMCI_SR_DCRCE))\r
91 \r
92 /** Max DMA size in a single transfer */\r
93 #define MAX_DMA_SIZE                (XDMAC_MAX_BT_SIZE & 0xFFFFFF00)\r
94 \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
107 \r
108 /**     @}*/\r
109 /*---------------------------------------------------------------------------\r
110  *         Local types\r
111  *---------------------------------------------------------------------------*/\r
112 \r
113 /*----------------------------------------------------------------------------\r
114  *         Local variable\r
115  *----------------------------------------------------------------------------*/\r
116 \r
117 //#define MCID_DBG  0\r
118 //static uint8_t bMcidDBG = 0;\r
119 \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
126 };\r
127 \r
128 /*---------------------------------------------------------------------------\r
129  *         Internal functions\r
130  *---------------------------------------------------------------------------*/\r
131 \r
132 /** \addtogroup mcid_functions\r
133  *@{\r
134  */\r
135 \r
136 /**\r
137  * Enable MCI peripheral access clock\r
138  */\r
139 static uint8_t _PeripheralEnable(uint32_t id)\r
140 {\r
141     if (PMC_IsPeriphEnabled(id)) return 0;\r
142     PMC_EnablePeripheral(id);\r
143     return 1;\r
144 }\r
145 \r
146 static void MciDma_Cb(uint32_t channel, sMcid* pArg)\r
147 {\r
148 \r
149     pArg->bOpStatus = 0;\r
150     memory_barrier();  \r
151     XDMAD_FreeChannel(pArg->pXdmad, channel);\r
152 }\r
153 \r
154 /**\r
155  * HSMCI DMA R/W prepare\r
156  */\r
157 static uint32_t _MciDMAPrepare(sMcid *pMcid, uint8_t bRd)\r
158 {\r
159     sXdmad *pXdmad = pMcid->pXdmad;\r
160     /* Allocate a channel */\r
161     if (bRd){\r
162         while(pMcid->bOpStatus);\r
163         pMcid->bOpStatus = 1;\r
164         pMcid->dwDmaCh = XDMAD_AllocateChannel(pXdmad, pMcid->bID, XDMAD_TRANSFER_MEMORY);\r
165     }\r
166     else { \r
167         while(pMcid->bOpStatus);\r
168         pMcid->bOpStatus = 2;\r
169         pMcid->dwDmaCh = XDMAD_AllocateChannel(pXdmad, XDMAD_TRANSFER_MEMORY, pMcid->bID);\r
170     }\r
171     if (pMcid->dwDmaCh == XDMAD_ALLOC_FAILED)\r
172     {\r
173         return SDMMC_ERROR_BUSY;\r
174     }\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
179 }\r
180 \r
181 /**\r
182  * HSMCI DMA R/W\r
183  * \return 1 if DMA started.\r
184  */\r
185 \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
191 #endif\r
192 static LinkedListDescriporView1 dmaLinkList[256];\r
193 \r
194 static uint32_t _MciDMA(sMcid *pMcid, uint32_t bFByte, uint8_t bRd)\r
195 {\r
196     Hsmci *pHw = pMcid->pMciHw;\r
197     sXdmad *pXdmad = pMcid->pXdmad;\r
198     sSdmmcCommand *pCmd = pMcid->pCmd;\r
199     sXdmadCfg xdmadRxCfg,xdmadTxCfg;\r
200     uint32_t xdmaCndc;\r
201     uint32_t hsmciId;\r
202     uint8_t i;\r
203     uint32_t totalSize = pCmd->wNbBlocks * pCmd->wBlockSize;\r
204     uint32_t maxXSize;\r
205     uint32_t memAddress;\r
206     uint8_t  bMByte;\r
207 \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
213         if (bRd){\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
224                 else\r
225                     dmaLinkList[i].mbr_nda = (uint32_t)&dmaLinkList[ i + 1 ];\r
226 \r
227             }\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
243                 return 0;\r
244             }\r
245             if (XDMAD_StartTransfer(pXdmad,pMcid->dwDmaCh)) {\r
246                 return 0;\r
247             }\r
248             //Write\r
249         } else {\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
260 \r
261             }\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
276 \r
277             if(XDMAD_ConfigureTransfer( pXdmad, pMcid->dwDmaCh, &xdmadTxCfg, xdmaCndc, (uint32_t)&dmaLinkList[0])){\r
278                 return 0;\r
279             }\r
280             if (XDMAD_StartTransfer(pXdmad,pMcid->dwDmaCh)) {\r
281                 return 0;\r
282             }\r
283         }\r
284     } else {\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
289         if (bRd)\r
290         {\r
291             maxXSize = bFByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);\r
292         }\r
293         /* M to P: Max size is M size */\r
294         else\r
295         {\r
296             maxXSize = bMByte ? MAX_DMA_SIZE : (MAX_DMA_SIZE * 4);\r
297         }\r
298         /* Update index */\r
299         pMcid->dwXSize = totalSize - pMcid->dwXfrNdx;\r
300         if (pMcid->dwXSize > maxXSize)\r
301         {\r
302             pMcid->dwXSize = maxXSize;\r
303         }\r
304         /* Prepare DMA transfer */\r
305         if (bRd)\r
306         {\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
321             memory_barrier();\r
322         }\r
323         else\r
324         {\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
339         }\r
340         XDMAD_StartTransfer(pXdmad, pMcid->dwDmaCh);\r
341     }\r
342 \r
343     return 1;\r
344 }\r
345 \r
346 /*----------------------------------------------------------------------------\r
347  *         Local functions\r
348  *----------------------------------------------------------------------------*/\r
349 \r
350 /**\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
354  */\r
355 static void MCI_Reset(sMcid *pMci, uint8_t keepSettings)\r
356 {\r
357     Hsmci *pMciHw = pMci->pMciHw;\r
358 \r
359     assert(pMci);\r
360     assert(pMci->pMciHw);\r
361 \r
362     HSMCI_Reset( pMciHw, keepSettings );\r
363 }\r
364 \r
365 /**\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
372  */\r
373 static uint32_t MCI_SetSpeed( sMcid* pMci, uint32_t mciSpeed, uint32_t mck )\r
374 {\r
375     Hsmci *pMciHw = pMci->pMciHw;\r
376     uint32_t clkdiv;\r
377     assert(pMci);\r
378     assert(pMciHw);\r
379 \r
380     if((mck % mciSpeed) == 0)\r
381     {\r
382         clkdiv = mck /mciSpeed;\r
383     } \r
384     else \r
385     {\r
386         clkdiv = ((mck + mciSpeed)/mciSpeed);\r
387     }\r
388     mciSpeed = mck / clkdiv;\r
389 \r
390     /* Modify MR */\r
391     HSMCI_DivCtrl( pMciHw, clkdiv, 0x7);\r
392     return (mciSpeed);\r
393 }\r
394 \r
395 /**\r
396 */\r
397 static void _FinishCmd( sMcid* pMcid, uint8_t bStatus )\r
398 {\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
404     {\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
408     }\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
415     {\r
416         (pCmd->fCallback)(pCmd->bStatus, pCmd->pArg);\r
417     }\r
418 }\r
419 \r
420 /*---------------------------------------------------------------------------\r
421  *      Exported functions\r
422  *---------------------------------------------------------------------------*/\r
423 \r
424 /**\r
425  * Select MCI slot.\r
426  */\r
427 void MCID_SetSlot(Hsmci *pMci, uint8_t slot)\r
428 \r
429 {\r
430     HSMCI_SetSlot(pMci, slot);\r
431 }\r
432 \r
433 /**\r
434  * Initialize MCI driver.\r
435  */\r
436 void MCID_Init(sMcid *pMcid,\r
437         Hsmci *pMci, uint8_t bID, uint32_t dwMck,\r
438         sXdmad *pXdmad,\r
439         uint8_t bPolling)\r
440 {\r
441     uint16_t clkDiv;\r
442 \r
443     assert(pMcid);\r
444     assert(pMci);\r
445 \r
446     /* Initialize driver struct */\r
447     pMcid->pMciHw    = pMci;\r
448     pMcid->pCmd      = NULL;\r
449 \r
450     pMcid->pXdmad         = pXdmad;\r
451     pMcid->dwDmaCh       = XDMAD_ALLOC_FAILED;\r
452     pMcid->dwXfrNdx      = 0;\r
453 \r
454     pMcid->dwMck     = dwMck;\r
455 \r
456     pMcid->bID       = bID;\r
457     pMcid->bPolling  = bPolling;\r
458     pMcid->bState    = MCID_IDLE;\r
459 \r
460     pMcid->bOpStatus    = 0;\r
461 \r
462     _PeripheralEnable( bID );\r
463 \r
464     MCI_RESET( pMci );\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
474 \r
475     HSMCI_Enable( pMci );\r
476     HSMCI_Configure( pMci, HSMCI_CFG_FIFOMODE | HSMCI_CFG_FERRCTRL );\r
477     /* Enable DMA */\r
478     HSMCI_EnableDma( pMci, 1 );\r
479     //_PeripheralDisable( bID );\r
480 }\r
481 \r
482 /**\r
483  * Lock the MCI driver for slot N access\r
484  */\r
485 uint32_t MCID_Lock(sMcid *pMcid, uint8_t bSlot)\r
486 {\r
487     Hsmci *pHw = pMcid->pMciHw;\r
488     uint32_t sdcr;\r
489 \r
490     assert(pMcid);\r
491     assert(pMcid->pMciHw);\r
492 \r
493     if (bSlot > 0)\r
494     {\r
495         return SDMMC_ERROR_PARAM;\r
496     }\r
497     if (pMcid->bState >= MCID_LOCKED)\r
498     {\r
499         return SDMMC_ERROR_LOCKED;\r
500     }\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
504     return SDMMC_OK;\r
505 }\r
506 \r
507 /**\r
508  * Release the driver.\r
509  */\r
510 uint32_t MCID_Release(sMcid *pMcid)\r
511 {\r
512     assert(pMcid);\r
513 \r
514     if (pMcid->bState >= MCID_CMD)\r
515     {\r
516         return SDMMC_ERROR_BUSY;\r
517     }\r
518     pMcid->bState = MCID_IDLE;\r
519     return SDMMC_OK;\r
520 }\r
521 \r
522 /**\r
523  * SD/MMC command.\r
524  */\r
525 uint32_t MCID_SendCmd(sMcid *pMcid, void *pCommand)\r
526 {\r
527     Hsmci *pHw = pMcid->pMciHw;\r
528     sSdmmcCommand *pCmd = pCommand;\r
529     uint32_t mr, ier;\r
530     uint32_t cmdr;\r
531 \r
532     assert(pMcid);\r
533     assert(pMcid->pMciHw);\r
534     assert(pCmd);\r
535     //printf("cmd = %d \n\r",pCmd->bCmd);\r
536     if (!MCID_IsCmdCompleted(pMcid))\r
537     {\r
538         return SDMMC_ERROR_BUSY;\r
539     }\r
540     pMcid->bState = MCID_CMD;\r
541     pMcid->pCmd   = pCmd;\r
542 \r
543     //_PeripheralEnable(pMcid->bID);\r
544     MCI_DISABLE(pHw);\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
550     }\r
551     /* Normal command: idle the bus */\r
552     else if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR)\r
553     {\r
554         HSMCI_ConfigureMode(pHw, mr);\r
555         ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;\r
556     }\r
557     /* No data transfer */\r
558     else if ((pCmd->cmdOp.wVal & SDMMC_CMD_CNODATA(0xF)) == SDMMC_CMD_CNODATA(0))\r
559     {\r
560         ier = HSMCI_IER_XFRDONE | STATUS_ERRORS_RESP;\r
561         /* R3 response, no CRC */\r
562         if (pCmd->cmdOp.bmBits.respType == 3)\r
563         {\r
564             ier &= ~(uint32_t)HSMCI_IER_RCRCE;\r
565         }\r
566     }\r
567     /* Data command but no following */\r
568     else if (pCmd->wNbBlocks == 0 || pCmd->pData == 0)\r
569     {\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
574     }\r
575     /* Command with data */\r
576     else\r
577     {\r
578         /* Setup block size */\r
579         if (pCmd->cmdOp.bmBits.sendCmd)\r
580         {\r
581             HSMCI_ConfigureTransfer(pHw, pCmd->wBlockSize, pCmd->wNbBlocks);\r
582         }\r
583         /* Block size is 0, force byte */\r
584         if (pCmd->wBlockSize == 0)\r
585             pCmd->wBlockSize = 1;\r
586 \r
587         /* Force byte transfer */\r
588         if (pCmd->wBlockSize & 0x3)\r
589         {\r
590             mr |= HSMCI_MR_FBYTE;\r
591         }\r
592         /* Set block size & MR */\r
593         HSMCI_ConfigureMode(pHw, mr | HSMCI_MR_WRPROOF\r
594                 | HSMCI_MR_RDPROOF\r
595                 | (pCmd->wBlockSize << 16));\r
596         memory_barrier();\r
597         /* DMA write */\r
598         if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_TX)\r
599         {\r
600             if (_MciDMAPrepare(pMcid, 0))\r
601             {\r
602                 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);\r
603                 return SDMMC_ERROR_BUSY;\r
604             }\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
608         }\r
609         else\r
610         {\r
611             if (_MciDMAPrepare(pMcid, 1))\r
612             {\r
613                 _FinishCmd(pMcid, SDMMC_ERROR_BUSY);\r
614                 return SDMMC_ERROR_BUSY;\r
615             }\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
619         }\r
620     }\r
621     MCI_ENABLE(pHw);\r
622     if (pCmd->cmdOp.wVal & (SDMMC_CMD_bmPOWERON | SDMMC_CMD_bmCOMMAND))\r
623     {\r
624         cmdr = pCmd->bCmd;\r
625 \r
626         if (pCmd->cmdOp.bmBits.powerON)\r
627         {\r
628             cmdr |= (HSMCI_CMDR_OPDCMD | HSMCI_CMDR_SPCMD_INIT);\r
629         }\r
630         if (pCmd->cmdOp.bmBits.odON)\r
631         {\r
632             cmdr |= HSMCI_CMDR_OPDCMD;\r
633         }\r
634         if (pCmd->cmdOp.bmBits.sendCmd)\r
635         {\r
636             cmdr |= HSMCI_CMDR_MAXLAT;\r
637         }\r
638         switch(pCmd->cmdOp.bmBits.xfrData)\r
639         {\r
640             case SDMMC_CMD_TX:\r
641                 if (pCmd->cmdOp.bmBits.ioCmd)\r
642                 {\r
643                     cmdr |= (pCmd->wBlockSize == 1) ?\r
644                         _CMDR_SDIO_BYTE :\r
645                         _CMDR_SDIO_BLOCK;\r
646                 }\r
647                 else\r
648                 {\r
649                     cmdr |= (pCmd->wNbBlocks == 1) ?\r
650                         _CMDR_SDMEM_SINGLE :\r
651                         _CMDR_SDMEM_MULTI;\r
652                 }\r
653                 break;\r
654 \r
655             case SDMMC_CMD_RX:\r
656                 if (pCmd->cmdOp.bmBits.ioCmd)\r
657                 {\r
658                     cmdr |= HSMCI_CMDR_TRDIR_READ\r
659                         |((pCmd->wBlockSize == 1) ?\r
660                                 _CMDR_SDIO_BYTE :\r
661                                 _CMDR_SDIO_BLOCK)\r
662                         ;\r
663                 }\r
664                 else\r
665                 {\r
666                     cmdr |= HSMCI_CMDR_TRDIR_READ\r
667                         |((pCmd->wNbBlocks == 1) ?\r
668                                 _CMDR_SDMEM_SINGLE :\r
669                                 _CMDR_SDMEM_MULTI)\r
670                         ;\r
671                 }\r
672                 break;\r
673 \r
674             case SDMMC_CMD_STOPXFR:\r
675                 cmdr |= HSMCI_CMDR_TRCMD_STOP_DATA;\r
676                 break;\r
677 \r
678         }\r
679         switch(pCmd->cmdOp.bmBits.respType)\r
680         {\r
681             case 3: case 4:\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
686                 break;\r
687             case 2:\r
688                 cmdr |= HSMCI_CMDR_RSPTYP_136_BIT;\r
689                 break;\r
690                 /* No response, ignore RTOE */\r
691             default:\r
692                 ier &= ~(uint32_t)HSMCI_IER_RTOE;\r
693         }\r
694 \r
695         pHw->HSMCI_ARGR = pCmd->dwArg;\r
696         pHw->HSMCI_CMDR = cmdr;\r
697     }\r
698 \r
699     /* Ignore CRC error for R3 & R4 */\r
700     if (pCmd->cmdOp.bmBits.xfrData == SDMMC_CMD_STOPXFR)\r
701     {\r
702         ier &= ~STATUS_ERRORS_DATA;\r
703     }\r
704 \r
705     /* Enable status flags */\r
706     HSMCI_EnableIt(pHw, ier);\r
707 \r
708     return SDMMC_OK;\r
709 }\r
710 static uint32_t dwMsk;\r
711 /**\r
712  * Process pending events on the given MCI driver.\r
713  */\r
714 void MCID_Handler(sMcid *pMcid)\r
715 {\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
720     assert(pMcid);\r
721     assert(pMcid->pMciHw);\r
722 \r
723     /* Do nothing if no pending command */\r
724     if (pCmd == NULL)\r
725     {\r
726         if (pMcid->bState >= MCID_CMD)\r
727         {\r
728             pMcid->bState = MCID_LOCKED;\r
729         }\r
730         return;\r
731     }\r
732 \r
733     /* Read status */\r
734     dwSr  = HSMCI_GetStatus(pHw);\r
735     dwMsk = HSMCI_GetItMask(pHw);\r
736     dwMaskedSr = dwSr & dwMsk;\r
737     /* Check errors */\r
738     if (dwMaskedSr & STATUS_ERRORS)\r
739     {\r
740         if (dwMaskedSr & HSMCI_SR_RTOE)\r
741         {\r
742             pCmd->bStatus = SDMMC_ERROR_NORESPONSE;\r
743         }\r
744 \r
745         if (pCmd->bCmd != 12) pMcid->bState = MCID_ERROR;\r
746         //pMcid->bState = MCID_ERROR;\r
747     }\r
748     dwMsk &= ~STATUS_ERRORS;\r
749 \r
750     /* Check command complete */\r
751     if (dwMaskedSr & HSMCI_SR_CMDRDY)\r
752     {   \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
756     }\r
757 \r
758     /* Check if not busy */\r
759     if (dwMaskedSr & HSMCI_SR_NOTBUSY)\r
760     {\r
761         //printf("NOTBUSY ");\r
762         HSMCI_DisableIt(pHw, HSMCI_IDR_NOTBUSY);\r
763         dwMsk &= ~(uint32_t)HSMCI_IMR_NOTBUSY;\r
764     }\r
765     /* Check if TX ready */\r
766     if (dwMaskedSr & HSMCI_SR_TXRDY)\r
767     {    \r
768         // printf("TXRDY ");\r
769         dwMsk &= ~(uint32_t)HSMCI_IMR_TXRDY;\r
770     }\r
771     /* Check if FIFO empty (all data sent) */\r
772     if (dwMaskedSr & HSMCI_SR_FIFOEMPTY)\r
773     {\r
774 \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
779     }\r
780 \r
781     /* Check if DMA finished */\r
782     if (dwMaskedSr & HSMCI_SR_XFRDONE)\r
783     {\r
784 \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
788     }\r
789 \r
790     /* All none error mask done, complete the command */\r
791     if (0 == dwMsk || pMcid->bState == MCID_ERROR)\r
792     {\r
793         /* Error reset */\r
794         if (pMcid->bState == MCID_ERROR)\r
795         {\r
796             MCI_Reset(pMcid, 1);\r
797         }\r
798         else \r
799         {\r
800             pCmd->bStatus = SDMMC_SUCCESS;\r
801 \r
802             if (pCmd->pResp)\r
803             {\r
804                 uint8_t bRspSize, i;\r
805                 switch(pCmd->cmdOp.bmBits.respType)\r
806                 {\r
807                     case 1: case 3: case 4: case 5: case 6: case 7:\r
808                         bRspSize = 1;\r
809                         break;\r
810 \r
811                     case 2:\r
812                         bRspSize = 4;\r
813                         break;\r
814 \r
815                     default:\r
816                         bRspSize = 0;\r
817                 }\r
818                 for (i = 0; i < bRspSize; i ++)\r
819                 {\r
820                     pCmd->pResp[i] = HSMCI_GetResponse(pHw);\r
821                 }\r
822             }\r
823         }\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
829         memory_barrier();\r
830         _FinishCmd(pMcid, pCmd->bStatus);\r
831     }\r
832 }\r
833 \r
834 /**\r
835  * Cancel pending SD/MMC command.\r
836  */\r
837 uint32_t MCID_CancelCmd(sMcid *pMcid)\r
838 {\r
839     if (pMcid->bState == MCID_IDLE)\r
840     {\r
841         return SDMMC_ERROR_STATE;\r
842     }\r
843     if (pMcid->bState == MCID_CMD)\r
844     {\r
845         /* Cancel ... */\r
846         MCI_Reset(pMcid, 1);\r
847         /* Command is finished */\r
848         _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);\r
849     }\r
850     return SDMMC_OK;\r
851 }\r
852 \r
853 /**\r
854  * Reset MCID and disable HW\r
855  */\r
856 void MCID_Reset(sMcid * pMcid)\r
857 {\r
858     Hsmci *pHw = pMcid->pMciHw;\r
859 \r
860     MCID_CancelCmd(pMcid);\r
861 \r
862     //_PeripheralEnable(pMcid->bID);\r
863 \r
864     /* Disable */\r
865     MCI_DISABLE(pHw);\r
866     /* MR reset */\r
867     HSMCI_ConfigureMode(pHw, HSMCI_GetMode(pHw) & (HSMCI_MR_CLKDIV_Msk\r
868                 | HSMCI_MR_PWSDIV_Msk));\r
869     /* BLKR reset */\r
870     HSMCI_ConfigureTransfer(pHw, 0, 0);\r
871 \r
872     /* Cancel ... */\r
873     MCI_Reset(pMcid, 1);\r
874     //_PeripheralDisable(pMcid->bID);\r
875 \r
876     if (pMcid->bState == MCID_CMD)\r
877     {\r
878         /* Command is finished */\r
879         _FinishCmd(pMcid, SDMMC_ERROR_USER_CANCEL);\r
880     }\r
881 }\r
882 \r
883 /**\r
884  * Check if the command is finished\r
885  */\r
886 uint32_t MCID_IsCmdCompleted(sMcid *pMcid)\r
887 {\r
888     sSdmmcCommand *pCmd = pMcid->pCmd;\r
889 \r
890     if (pMcid->bPolling)\r
891     {\r
892         MCID_Handler(pMcid);\r
893     }\r
894     if (pMcid->bState == MCID_CMD)\r
895     {\r
896         return 0;\r
897     }\r
898     if (pCmd)\r
899     {\r
900         return 0;\r
901     }\r
902     return 1;\r
903 }\r
904 \r
905 /**\r
906  * IO control functions\r
907  */\r
908 uint32_t MCID_IOCtrl(sMcid *pMcid, uint32_t bCtl, uint32_t param)\r
909 {\r
910     Hsmci *pMciHw = pMcid->pMciHw;\r
911     assert(pMcid);\r
912     assert(pMcid->pMciHw);\r
913 \r
914     //mciDis = _PeripheralEnable(pMcid->bID);\r
915 \r
916     switch (bCtl)\r
917     {\r
918         case SDMMC_IOCTL_BUSY_CHECK:\r
919             *(uint32_t*)param = !MCID_IsCmdCompleted(pMcid);\r
920             break;\r
921 \r
922         case SDMMC_IOCTL_POWER:\r
923             return SDMMC_ERROR_NOT_SUPPORT;\r
924 \r
925         case SDMMC_IOCTL_RESET:\r
926             MCID_Reset(pMcid);\r
927             return SDMMC_SUCCESS;\r
928 \r
929         case SDMMC_IOCTL_CANCEL_CMD:\r
930             return MCID_CancelCmd(pMcid);\r
931 \r
932         case SDMMC_IOCTL_SET_CLOCK:\r
933             *(uint32_t*)param = MCI_SetSpeed(pMcid,\r
934                     *(uint32_t*)param,\r
935                     pMcid->dwMck);\r
936             break;\r
937 \r
938         case SDMMC_IOCTL_SET_HSMODE:\r
939             HSMCI_HsEnable( pMciHw, *(uint32_t*)param );\r
940             *(uint32_t*)param = HSMCI_IsHsEnabled( pMciHw );\r
941 \r
942             break;\r
943 \r
944         case SDMMC_IOCTL_SET_BUSMODE:\r
945             HSMCI_SetBusWidth( pMciHw, *(uint32_t*)param );\r
946             break;\r
947 \r
948         case SDMMC_IOCTL_GET_BUSMODE:\r
949             //*(uint32_t*)param = 8; /* Max 4-bit bus */\r
950             break;\r
951 \r
952         case SDMMC_IOCTL_GET_HSMODE:\r
953             *(uint32_t*)param = 1; /* Supported */\r
954             break;\r
955 \r
956         default:\r
957             return SDMMC_ERROR_NOT_SUPPORT;\r
958 \r
959     }\r
960     return SDMMC_OK;\r
961 }\r
962 \r
963 /**\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
966  */\r
967 void SDD_InitializeSdmmcMode(sSdCard * pSd,void * pDrv,uint8_t bSlot)\r
968 {\r
969     SDD_Initialize(pSd, pDrv, bSlot, &sdHal);\r
970 }\r
971 \r
972 /**@}*/\r
973 \r