1 /*************************************************************************
3 * Used with ICCARM and AARM.
5 * (c) Copyright IAR Systems 2005
11 * 1. Data : July 1, 2005
12 * Author : Stanimir Bonev
13 * Description : Create
17 * (C) Joel Winarske, 2006,2007
18 **************************************************************************/
19 #include <stdio.h> // ###
25 #define MMC_RET_ERROR(Res) do { mmcLastError = Res; return (MmcCardError); } while (0)
26 #define MMC_RET_DATA_ERR(Res) do { mmcLastError = Res; return (MmcDataError); } while (0)
28 #define CSD_GET_TRAN_SPEED_EXP() (mmcSdCsd [ 3] & 0x07)
29 #define CSD_GET_TRAN_SPEED_MANT() ((mmcSdCsd [ 3] & 0xF8) >> 3)
30 #define CSD_GET_NSAC() (mmcSdCsd [ 2])
31 #define CSD_GET_TAAC_EXP() (mmcSdCsd [ 1] & 0x7)
32 #define CSD_GET_TAAC_MANT() ((mmcSdCsd [ 1] & 0xF8) >> 3)
33 #define CSD_GET_R2W_FACTOR() ((mmcSdCsd [12] & 0x1C) >> 2)
34 #define CSD_GET_READ_BL_LEN() (mmcSdCsd [ 5] & 0x0F)
35 #define CSD_GET_C_SIZE() (((mmcSdCsd [ 6] & 0x03) << 10) + (mmcSdCsd [7] << 2) + ((mmcSdCsd [8] & 0xc0) >> 6))
36 #define CSD_GET_C_SIZE_MULT() (((mmcSdCsd [ 9] & 0x03) << 1) + ((mmcSdCsd [10] & 0x80) >> 7))
37 #define CSD_GET_PERM_WRITE_PROTECT() ((mmcSdCsd [14] & 0x20) >> 5)
38 #define CSD_GET_TMP_WRITE_PROTECT() ((mmcSdCsd [14] & 0x10) >> 4)
40 static const U32 mmcTransfExp [] =
52 static const U32 mmmcAccessTime [] =
64 static const U32 mmcCsdMant [] =
66 0UL,10UL,12UL,13UL,15UL,
76 static const U32 mmcAccessTimeMant [] =
78 0UL,100UL,83UL,77UL,67UL,
88 static const mmcCommads_t mmcCmd [CMD_END] =
90 { 0x40, MmcNoArg, MmcR1 }, // CMD0
91 { 0x41, MmcNoArg, MmcR1 }, // CMD1
92 { 0x49, MmcNoArg, MmcR1 }, // CMD9
93 { 0x4A, MmcNoArg, MmcR1 }, // CMD10
94 { 0x4C, MmcNoArg, MmcR1 }, // CMD12
95 { 0x4D, MmcNoArg, MmcR2 }, // CMD13
96 { 0x50, MmcBlockLen, MmcR1 }, // CMD16
97 { 0x51, MmcDataAdd, MmcR1 }, // CMD17
98 { 0x52, MmcDataAdd, MmcR1 }, // CMD18
99 { 0x58, MmcDataAdd, MmcR1 }, // CMD24
100 { 0x59, MmcDataAdd, MmcR1 }, // CMD25
101 { 0x5B, MmcNoArg, MmcR1 }, // CMD27
102 { 0x5C, MmcDataAdd, MmcR1b}, // CMD28
103 { 0x5D, MmcDataAdd, MmcR1b}, // CMD29
104 { 0x5E, MmcDataAdd, MmcR1 }, // CMD30
105 { 0x60, MmcDataAdd, MmcR1 }, // CMD32
106 { 0x61, MmcDataAdd, MmcR1 }, // CMD33
107 { 0x62, MmcDataAdd, MmcR1 }, // CMD34
108 { 0x63, MmcDataAdd, MmcR1 }, // CMD35
109 { 0x64, MmcDataAdd, MmcR1 }, // CMD36
110 { 0x65, MmcDataAdd, MmcR1 }, // CMD37
111 { 0x66, MmcDummyWord, MmcR1b}, // CMD38
112 { 0x6A, MmcDummyWord, MmcR1b}, // CMD42
113 { 0x77, MmcNoArg, MmcR1 }, // CMD55
114 { 0x78, MmcNoArg, MmcR1 }, // CMD56
115 { 0x7A, MmcNoArg, MmcR3 }, // CMD58
116 { 0x7B, MmcDummyWord, MmcR1 }, // CMD59
117 { 0x69, MmcNoArg, MmcR1 } // ACMD41
120 static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
121 static DiskStatus_t mmcDskStatus;
122 static U32 mmcLastError;
125 static U8 mmcSdCsd [16];
130 static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg);
131 static U32 mmcSetBlockLen (U32 length);
132 static void mmcCSDImplement (void);
133 static mmcState_t mmcInitMedia (void);
134 static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command);
135 static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length);
136 static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length);
137 static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length);
139 /*************************************************************************
140 * Function Name: mmcSendCmd
141 * Parameters: MmcSpiCmdInd_t ComdInd,U32 Arg
145 * Description: MMC commands implemet
147 *************************************************************************/
148 static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg)
161 spiTransferByte (mmcCmd [ComdInd].TxData);
164 // Send command's arguments
166 if (mmcCmd [ComdInd].Arg == MmcNoArg)
168 spiTransferByte (0x00);
169 spiTransferByte (0x00);
170 spiTransferByte (0x00);
171 spiTransferByte (0x00);
175 spiTransferByte (Arg >> 24);
176 spiTransferByte (Arg >> 16);
177 spiTransferByte (Arg >> 8);
178 spiTransferByte (Arg);
185 spiTransferByte (0x95);
187 spiTransferByte (0xff);
189 for (i = 9; i && (ch == 0xff); --i)
190 ch = spiTransferByte (0xff);
198 switch (mmcCmd [ComdInd].Resp)
204 for (busy = 0, i = Twr; i && (busy != 0xff); --i)
205 busy = spiTransferByte (0xff);
213 Arg = ((U32) ch << 8) & 0x0000FF00;
214 Arg |= spiTransferByte (0xff) & 0xff;
219 Arg = ((U32) ch << 24) & 0xff000000;
220 Arg |= ((U32) spiTransferByte (0xff) << 16) & 0x00FF0000;
221 Arg |= ((U32) spiTransferByte (0xff) << 8 ) & 0x0000FF00;
222 Arg |= spiTransferByte (0xff) & 0xff;
227 /*************************************************************************
228 * Function Name: mmcSetBlockLen
229 * Parameters: U32 Length
233 * Description: Set Block length Return command's result
235 *************************************************************************/
236 static U32 mmcSetBlockLen (U32 length)
238 U32 res = mmcSendCmd (CMD16, length);
243 /*************************************************************************
244 * Function Name: mmcCSDImplement
249 * Description: Implemet data from CSD
251 *************************************************************************/
252 static void mmcCSDImplement (void)
257 // Calculate SPI max clock
259 frequency = mmcTransfExp [CSD_GET_TRAN_SPEED_EXP ()] * mmcCsdMant [CSD_GET_TRAN_SPEED_MANT ()];
261 if (frequency > 20000000)
262 frequency = 20000000;
264 frequency = spiSetClockFreq (frequency);
266 if (mmcDskStatus.DiskType == DiskMMC)
268 Tnac = mmmcAccessTime [CSD_GET_TAAC_EXP ()] * mmcAccessTimeMant [CSD_GET_TAAC_MANT ()];
269 Tnac = frequency / Tnac;
270 Tnac += 1 << (CSD_GET_NSAC () + 4);
272 Twr = Tnac * CSD_GET_R2W_FACTOR ();
276 Tnac = frequency / SD_READ_TIME_OUT;
277 Twr = frequency / SD_WRITE_TIME_OUT;
280 mmcDskStatus.BlockSize = 1 << CSD_GET_READ_BL_LEN ();
281 mmcDskStatus.BlockNumb = (CSD_GET_C_SIZE () + 1) * (4 << CSD_GET_C_SIZE_MULT ());
282 mmcDskStatus.WriteProtect = spiWriteProtect () | CSD_GET_PERM_WRITE_PROTECT () | CSD_GET_TMP_WRITE_PROTECT ();
285 /*************************************************************************
286 * Function Name: mmcInitMedia
291 * Description: MMC detect and initialize
293 *************************************************************************/
294 static mmcState_t mmcInitMedia (void)
302 return (MmcNoPresent);
305 // Clock Freq. Identification Mode < 400kHz
307 spiSetClockFreq (IdentificationModeClock);
310 // Set maximum time out
312 Tnac = IdentificationModeClock / SD_READ_TIME_OUT;
315 // Power up cycles. After power up at least 74 clock cycles are required
316 // prior to starting bus communication
318 for (i = 0; i < 2; i++)
322 for (res = 10; res; --res)
323 spiTransferByte (0xff);
326 // CMD0 (Go to IDLE) to put MMC in SPI mode
328 res = mmcSendCmd (CMD0, 0);
331 if (res == MMC_IDLE_STATE)
335 if (res != MMC_IDLE_STATE)
336 return (MmcNoResponse);
339 // Determinate Card type SD or MMC
341 mmcDskStatus.DiskType = DiskMMC;
343 for (i = 100; i; --i)
346 spiTransferByte (0xff);
347 res = mmcSendCmd (CMD55, 0);
350 spiTransferByte (0xff);
351 res = mmcSendCmd (ACMD41, 0);
354 if (res & MMC_ILLEGAL_CMD)
357 // MMC card may be CMD1 for MMC Init sequence will be complete within 500ms
359 for (i = 100; i; --i)
362 spiTransferByte (0xff);
363 res = mmcSendCmd (CMD1, 0);
376 mmcDskStatus.DiskType = DiskSD;
384 return (MmcNoResponse);
387 // Read CSD. CSD must always be valid
389 if ((res = mmcReadCardInfo (mmcSdCsd, CMD9)) != MmcOk)
390 return (MmcNoResponse);
393 // Implement CSD data, and set block size
396 mmcSetBlockLen (mmcDskStatus.BlockSize);
398 // mmcDecode (mmcSdCsd); // ###
403 /*************************************************************************
404 * Function Name: mmcReadCardInfo
405 * Parameters: U8 *pData,
406 * mmcSpiCmdInd_t Command - CMD9, CMD10 are only allowed
410 * Description: Read CSD or CID registers depend of commoand
412 *************************************************************************/
413 static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command)
425 return (MmmcParameterError);
429 spiTransferByte (0xff);
431 if ((res = mmcSendCmd (Command, 0)) == MMC_OK)
435 if (((res = spiTransferByte (0xff)) | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
437 // printf ("line %d: spiTransferByte returned 0x%x\n", __LINE__, res); // ###
438 MMC_RET_DATA_ERR (res);
440 else if (res == MMC_DATA_TOKEN)
442 for (i = 0; i <16 ; ++i)
443 *pData++ = spiTransferByte (0xff);
448 spiTransferByte (0xff);
449 spiTransferByte (0xff);
456 // printf ("line %d: mmcSendCmd returned %d\n", __LINE__, res); // ###
462 /*************************************************************************
463 * Function Name: mmcRead
464 * Parameters: U8 *pData, U32 Add, U32 Length
468 * Description: Read from a MMC
470 *************************************************************************/
471 static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length)
477 // For synchronization
480 spiTransferByte (0xff);
481 res = mmcSendCmd (CMD17, Add);
485 for (i = Tnac; i; --i)
487 res = spiTransferByte (0xff);
489 if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
490 MMC_RET_DATA_ERR (res);
491 else if (res == MMC_DATA_TOKEN)
493 spiReceiveBlock (pData, Length);
498 spiTransferByte (0xff);
499 spiTransferByte (0xff);
506 return (MmcNoResponse);
513 /*************************************************************************
514 * Function Name: mmcWrite
515 * Parameters: U8 *pData, U32 Add, U32 Length
519 * Description: Write to a MMC
521 *************************************************************************/
522 static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length)
528 // For synchronization
531 spiTransferByte (0xff);
533 if ((res = mmcSendCmd (CMD24, Add)) == MMC_OK)
535 spiTransferByte (0xff);
536 spiTransferByte (MMC_DATA_TOKEN);
537 spiSendBlock (pData, Length);
542 spiTransferByte (0xff);
543 spiTransferByte (0xff);
545 if ((spiTransferByte (0xff) & 0x1F) != 0x05)
548 for (i = Twr; i ;i--)
549 if (spiTransferByte (0xff) == 0xff)
555 return (MmcNoResponse);
564 /*************************************************************************
565 * Function Name: mmcVerify
566 * Parameters: U8 *pData, U32 Add, U32 Length
570 * Description: Verify on a MMC
572 *************************************************************************/
573 static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length)
578 // For synchronization
581 spiTransferByte (0xff);
583 if ((res = mmcSendCmd (CMD17, Add)) == MMC_OK)
585 for (i = Tnac; i; --i)
587 res = spiTransferByte (0xff);
589 if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
590 MMC_RET_DATA_ERR (res);
591 else if (res == MMC_DATA_TOKEN)
593 for (res = 0, i = 0; i < Length; ++i, ++pData)
595 *pData ^= spiTransferByte (0xff);
604 spiTransferByte (0xff);
605 spiTransferByte (0xff);
607 spiTransferByte (0xff);
608 spiTransferByte (0xff);
611 return (MmcMiscompare);
617 return (MmcNoResponse);
626 DSTATUS diskInitialize (U8 drv __attribute__ ((unused)))
628 mmcDskStatus.BlockNumb = mmcDskStatus.BlockSize = mmcLastError = 0;
638 switch (mmcInitMedia ())
643 mmcDskStatus.DiskStatus = DiskCommandPass;
644 mmcDskStatus.MediaChanged = TRUE;
646 if (mmcDskStatus.WriteProtect)
654 mmcDskStatus.DiskStatus = DiskNotReady;
656 if (mmcDskStatus.WriteProtect)
663 mmcDskStatus.DiskStatus = DiskNotPresent;
675 DSTATUS diskShutdown (void)
685 DSTATUS diskStatus (U8 drv __attribute__ ((unused)))
693 DRESULT diskRead (U8 disk __attribute__ ((unused)), U8 *buff, U32 sector, U8 count)
697 if (Stat & STA_NOINIT)
702 res = mmcRead (buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
713 #if _FS_READONLY == 0
714 DRESULT diskWrite (U8 disk __attribute__ ((unused)), const U8 *buff, U32 sector, U8 count)
718 if (Stat & STA_NOINIT)
720 if (Stat & STA_PROTECT)
725 res = mmcWrite ((U8 *) buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
737 DRESULT diskIoctl (U8 drv, U8 ctrl, void *buff)
746 if (Stat & STA_NOINIT)
753 case GET_SECTOR_COUNT :
755 mmcState_t jcwres; // ###
756 if ((jcwres = mmcReadCardInfo (csd, CMD9)) == MmcOk)
761 if ((csd [0] >> 6) == 1)
763 csize = csd [9] + ((U16)csd [8] << 8) + 1;
764 *(U32 *) buff = (U32) csize << 10;
767 // MMC or SDC ver 1.XX
771 n = (csd [5] & 15) + ((csd [10] & 128) >> 7) + ((csd [9] & 3) << 1) + 2;
772 csize = (csd [8] >> 6) + ((U16) csd [7] << 2) + ((U16) (csd [6] & 3) << 10) + 1;
773 *(U32 *) buff = (U32) csize << (n - 9);
779 // printf ("line %d: mmcReadCardInfo returned %d\n", __LINE__, jcwres); // ###
783 case GET_SECTOR_SIZE :
792 if (spiWaitReady () == 0xff)
799 if (mmcReadCardInfo (buff, CMD9) == MmcOk)
806 if (mmcReadCardInfo (buff, CMD10) == MmcOk)
815 case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
829 static void mmcDump (U8 *buff, U32 ofs, U8 cnt)
833 printf ("\n\r%08X ", ofs);
835 for (n = 0; n < cnt; n++)
836 printf (" %02X", buff [n]);
840 for (n = 0; n < cnt; n++)
842 if ((buff [n] < 0x20) || (buff [n] >= 0x7F))
851 typedef struct csd_11_s
853 unsigned int not_used_1 : 2; // 0..1 [121:120] 0x44
854 unsigned int mmc_prot : 4; // 2..5 [125:122]
855 unsigned int csd_structure : 2; // 6..7 [127:126]
856 unsigned int taac : 8; // 0..7 [119:112] 0x26
857 unsigned int nsac : 8; // 0..7 [111:104] 0x00
858 unsigned int tran_speed : 8; // 0..7 [103:96] 0x2a
859 unsigned int ccc_hi : 8; // 0..7 [95:88] 0x1f
860 unsigned int read_bl_len : 4; // 0..3 [83:80] 0xf9
861 unsigned int ccc_lo : 4; // 4..7 [87:84]
863 unsigned int c_size_hi : 2; // 0..1 [73:72] 0x83
864 unsigned int not_used_2 : 2; // 2..3 [75:74]
865 unsigned int dsr_imp : 1; // 4..4 [76:76]
866 unsigned int read_blk_misalign : 1; // 5..5 [77:77]
867 unsigned int write_blk_misalign : 1; // 6..6 [78:78]
868 unsigned int read_bl_partial : 1; // 7..7 [79:79]
869 unsigned int c_size_mid : 8; // 0..7 [71:64] 0xd3
870 unsigned int vdd_r_curr_max : 3; // 0..1 [58:56] 0xe3
871 unsigned int vdd_r_curr_min : 3; // 2..5 [61:59]
872 unsigned int c_size_lo : 2; // 6..7 [63:62]
874 unsigned int c_size_mult_hi : 2; // 0..1 [49:48] 0x91
875 unsigned int vdd_w_curr_max : 3; // 2..4 [52:50]
876 unsigned int vdd_w_curr_min : 3; // 4..7 [55:53]
877 unsigned int erase_grp_size_lo : 2; // 0..1 [41:40] 0x83
878 unsigned int sector_size : 5; // 2..6 [46:42]
879 unsigned int c_size_mult_lo : 1; // 7..7 [47:47]
880 unsigned int wp_grp_size : 5; // 0..4 [36:32] 0xff
881 unsigned int erase_grp_size_hi : 3; // 5..7 [39:37]
883 unsigned int write_bl_len_hi : 2; // 0..1 [25:24] 0x92
884 unsigned int r2w_factor : 3; // 2..4 [28:26]
885 unsigned int default_ecc : 2; // 5..6 [30:29]
886 unsigned int wp_grp_enable : 1; // 7..7 [31:31]
887 unsigned int not_used_3 : 5; // 0..4 [20:16] 0x40
888 unsigned int write_bl_partial : 1; // 5..5 [21:21]
889 unsigned int write_bl_len_lo : 2; // 6..7 [23:22]
891 unsigned int ecc : 2; // 0..1 [9:8] 0x40
892 unsigned int not_used_5 : 2; // 2..3 [11:10]
893 unsigned int tmp_write_protect : 1; // 4..4 [12:12]
894 unsigned int perm_write_protect : 1; // 5..5 [13:13]
895 unsigned int copy : 1; // 6..6 [14:14]
896 unsigned int not_used_4 : 1; // 7..7 [15:15]
898 unsigned int notused_6 : 1; // 0..0 [0:0] 0x67
899 unsigned int crc : 7; // 1..7 [7:1]
901 __attribute__ ((packed)) csd_11_t;
903 static void mmcDecode (U8 *buffer)
905 csd_11_t *p = (csd_11_t *) buffer;
908 printf ("sizeof (csd_11_t) : %lu\n", sizeof (csd_11_t));
909 printf ("CSD structure version : 1.%d\n", p->csd_structure);
910 printf ("MMC protocol version : %d\n", p->mmc_prot);
911 printf ("TAAC : 0x%02x\n", p->taac);
912 printf ("NSAC : 0x%02x\n", p->nsac);
913 printf ("TRAN_SPEED : 0x%02x\n", p->tran_speed);
914 printf ("CCC : 0x%03x\n", (p->ccc_hi << 4) | p->ccc_lo);
915 printf ("READ_BL_LEN : %d\n", p->read_bl_len);
916 printf ("READ_BL_PARTIAL : %d\n", p->read_bl_partial);
917 printf ("WRITE_BLK_MISALIGN : %d\n", p->write_blk_misalign);
918 printf ("READ_BLK_MISALIGN : %d\n", p->read_blk_misalign);
919 printf ("DSR_IMP : %d\n", p->read_blk_misalign);
920 printf ("C_SIZE : %d\n", (p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo);
921 printf ("VDD_R_CURR_MIN : %d\n", p->vdd_r_curr_min);
922 printf ("VDD_R_CURR_MAX : %d\n", p->vdd_r_curr_max);
923 printf ("VDD_W_CURR_MIN : %d\n", p->vdd_w_curr_min);
924 printf ("VDD_W_CURR_MAX : %d\n", p->vdd_w_curr_max);
925 printf ("VDD_W_CURR_MAX : %d\n", p->vdd_w_curr_max);
926 printf ("C_SIZE_MULT : %d\n", (p->c_size_mult_hi << 1) | p->c_size_mult_lo);
927 printf ("SECTOR_SIZE : %d\n", p->sector_size);
928 printf ("ERASE_GRP_SIZE : %d\n", (p->erase_grp_size_hi << 2) | p->erase_grp_size_lo);
929 printf ("WP_GRP_SIZE : %d\n", p->wp_grp_size);
930 printf ("WP_GRP_ENABLE : %d\n", p->wp_grp_enable);
931 printf ("DEFAULT_ECC : %d\n", p->default_ecc);
932 printf ("R2W_FACTOR : %d\n", p->r2w_factor);
933 printf ("WRITE_BL_LEN : %d\n", (p->write_bl_len_hi << 2) | p->write_bl_len_lo);
934 printf ("WRITE_BL_PARTIAL : %d\n", p->write_bl_partial);
935 printf ("COPY : %d\n", p->copy);
936 printf ("PERM_WRITE_PROTECT : %d\n", p->perm_write_protect);
937 printf ("TMP_WRITE_PROTECT : %d\n", p->tmp_write_protect);
938 printf ("ECC : %d\n", p->ecc);
939 printf ("MEDIA SIZE : %u\n", (U32) (((p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo) + 1) *
940 (U32) (4 << ((p->c_size_mult_hi << 1) | p->c_size_mult_lo)) *
941 (U32) (1 << (p->read_bl_len)));