00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00059 #include <cfg/arch.h>
00060 #include <cfg/arch/gpio.h>
00061
00062 #include <errno.h>
00063 #include <string.h>
00064 #include <stdlib.h>
00065
00066 #include <sys/heap.h>
00067 #include <sys/timer.h>
00068 #include <sys/event.h>
00069 #include <fs/dospart.h>
00070 #include <fs/fs.h>
00071
00072 #include <dev/blockdev.h>
00073 #include <dev/mmcard.h>
00074 #include <dev/at91_mci.h>
00075
00076
00077 #if 0
00078
00079 #define NUTDEBUG
00080 #include <stdio.h>
00081 #endif
00082
00087
00088 #ifndef MMC_BLOCK_SIZE
00089 #define MMC_BLOCK_SIZE 512
00090 #endif
00091
00092 #ifndef MMC_PINS_A
00093 #define MMC_PINS_A _BV(PA8_MCCK_A)
00094 #endif
00095
00096 #ifndef MMC_PINS_B
00097 #define MMC_PINS_B _BV(PA1_MCCDB_B) | _BV(PA0_MCDB0_B) | _BV(PA5_MCDB1_B) | _BV(PA4_MCDB2_B) | _BV(PA3_MCDB3_B)
00098 #endif
00099
00100 #define MCICMD_ALL_SEND_CID (MMCMD_ALL_SEND_CID | MCI_OPDCMD | MCI_MAXLAT | MCI_RSPTYP_136)
00101 #define MCICMD_DESELECT_CARD (MMCMD_SELECT_CARD)
00102 #define MCICMD_GO_IDLE_STATE (MMCMD_GO_IDLE_STATE)
00103 #define MCICMD_READ_SINGLE_BLOCK (MMCMD_READ_SINGLE_BLOCK | MCI_TRCMD_START | MCI_TRDIR | MCI_MAXLAT | MCI_RSPTYP_48)
00104 #define MCICMD_SELECT_CARD (MMCMD_SELECT_CARD | MCI_MAXLAT | MCI_RSPTYP_48)
00105 #define MCICMD_SEND_APP_CMD (MMCMD_SEND_APP_CMD | MCI_MAXLAT | MCI_RSPTYP_48)
00106 #define MCICMD_SEND_APP_OP_COND (MMCMD_SEND_APP_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00107 #define MCICMD_SEND_OP_COND (MMCMD_SEND_OP_COND | MCI_MAXLAT | MCI_RSPTYP_48)
00108 #define MCICMD_SEND_RELATIVE_ADDR (MMCMD_SEND_RELATIVE_ADDR | MCI_MAXLAT | MCI_RSPTYP_48)
00109 #define MCICMD_SEND_STATUS (MMCMD_SEND_STATUS | MCI_MAXLAT | MCI_RSPTYP_48)
00110 #define MCICMD_SET_BLOCKLEN (MMCMD_SET_BLOCKLEN | MCI_MAXLAT | MCI_RSPTYP_48)
00111 #define MCICMD_WRITE_BLOCK (MMCMD_WRITE_BLOCK | MCI_TRCMD_START | MCI_MAXLAT | MCI_RSPTYP_48)
00112
00113
00114 #define MCICMD_ERROR (MCI_UNRE | MCI_OVRE | MCI_DTOE | MCI_DCRCE | MCI_RTOE | MCI_RENDE | MCI_RCRCE | MCI_RDIRE | MCI_RINDE)
00115
00116 #define MCIFLG_SDCARD 0x00000001
00117 #define MCIFLG_4BIT 0x00000010
00118
00122 typedef struct _MCIFC {
00124 uint32_t ifc_config;
00126 uint32_t ifc_opcond;
00128 uint32_t ifc_reladdr;
00130 uint8_t *ifc_buff;
00132 uint32_t ifc_resp[4];
00134 uint32_t ifc_cid[4];
00135 } MCIFC;
00136
00140 typedef struct _MCIFCB {
00143 NUTDEVICE *fcb_fsdev;
00144
00147 DOSPART fcb_part;
00148
00156 uint32_t fcb_blknum;
00157
00167 uint8_t fcb_blkbuf[MMC_BLOCK_SIZE];
00168 } MCIFCB;
00169
00170
00171
00172
00173
00174
00175 static HANDLE mutex;
00176
00183 static void At91MciReset(int init)
00184 {
00185 uint32_t mode;
00186 uint32_t dtmo;
00187 uint32_t slot;
00188
00189
00190 outr(PMC_PCER, _BV(MCI_ID));
00191
00192 if (init) {
00193 outr(MCI_IDR, 0xFFFFFFFF);
00194
00195 dtmo = MCI_DTOMUL_1M | MCI_DTOCYC;
00196
00197 mode = MCI_RDPROOF | MCI_WRPROOF | MCI_PDCMODE | (2 << MCI_PWSDIV_LSB) | (128 << MCI_CLKDIV_LSB);
00198 slot = MCI_SDCSEL_SLOTB;
00199 } else {
00200
00201 dtmo = inr(MCI_DTOR);
00202 mode = inr(MCI_MR) & 0xffff;
00203 slot = inr(MCI_SDCR);
00204 }
00205
00206
00207 outr(MCI_CR, MCI_MCIDIS | MCI_SWRST);
00208
00209
00210 outr(MCI_DTOR, dtmo);
00211 outr(MCI_MR, mode);
00212 outr(MCI_SDCR, slot);
00213
00214
00215 outr(MCI_CR, MCI_MCIEN | MCI_PWSEN);
00216 }
00217
00226 static int At91MciInit(NUTDEVICE * dev)
00227 {
00228
00229 outr(PIOA_PDR, MMC_PINS_A | MMC_PINS_B);
00230
00231 outr(PIOA_ASR, MMC_PINS_A);
00232 outr(PIOA_BSR, MMC_PINS_B);
00233
00234 At91MciReset(1);
00235
00236 return 0;
00237 }
00238
00248 static uint32_t At91MciTxCmd(MCIFC * ifc, uint32_t cmd, uint32_t param)
00249 {
00250 uint32_t sr;
00251 uint32_t rl;
00252 uint32_t i;
00253 uint32_t wfs = MCI_CMDRDY;
00254
00255
00256
00257
00258 #ifdef NUTDEBUG
00259 printf("[Cmd%lu,%lx]", cmd & MCI_CMDNB, param);
00260 #endif
00261 outr(MCI_PTCR, PDC_TXTDIS | PDC_RXTDIS);
00262 outr(MCI_MR, inr(MCI_MR) & ~(MCI_BLKLEN | MCI_PDCMODE));
00263 outr(MCI_RCR, 0);
00264 outr(MCI_RNCR, 0);
00265 outr(MCI_TCR, 0);
00266 outr(MCI_TNCR, 0);
00267
00268 if (cmd & MCI_TRCMD_START) {
00269
00270 if (ifc->ifc_buff == NULL) {
00271 errno = EINVAL;
00272 return MCI_OVRE | MCI_UNRE;
00273 }
00274
00275 outr(MCI_MR, (inr(MCI_MR) & ~MCI_BLKLEN) | (MMC_BLOCK_SIZE << MCI_BLKLEN_LSB) | MCI_PDCMODE);
00276 if (cmd & MCI_TRDIR) {
00277
00278 outr(MCI_RPR, (uint32_t) ifc->ifc_buff);
00279 outr(MCI_RCR, MMC_BLOCK_SIZE / 4);
00280
00281 outr(MCI_PTCR, PDC_RXTEN);
00282
00283 wfs = MCI_ENDRX;
00284 } else {
00285
00286 outr(MCI_TPR, (uint32_t) ifc->ifc_buff);
00287 outr(MCI_TCR, MMC_BLOCK_SIZE / 4);
00288
00289 wfs = MCI_BLKE;
00290 }
00291 }
00292
00293 outr(MCI_ARGR, param);
00294 outr(MCI_CMDR, cmd);
00295
00296
00297 if ((cmd & (MCI_TRCMD_START | MCI_TRDIR)) == MCI_TRCMD_START) {
00298 outr(MCI_PTCR, PDC_TXTEN);
00299 }
00300
00301
00302 switch (cmd & MCI_RSPTYP) {
00303 case MCI_RSPTYP_48:
00304 rl = 2;
00305 break;
00306 case MCI_RSPTYP_136:
00307 rl = 4;
00308 break;
00309 default:
00310 rl = 0;
00311 break;
00312 }
00313
00314 while (((sr = inr(MCI_SR)) & wfs) == 0);
00315
00316 for (i = 0; i < rl; i++) {
00317 ifc->ifc_resp[i] = inr(MCI_RSPR);
00318 }
00319 #ifdef NUTDEBUG
00320 printf("[Sta=%lx][Rsp", sr);
00321 for (i = 0; i < rl; i++) {
00322 printf(" %lx", ifc->ifc_resp[i]);
00323 }
00324 printf("]\n");
00325 #endif
00326
00327 if (wfs & MCI_BLKE) {
00328 while ((inr(MCI_SR) & MCI_NOTBUSY) == 0);
00329 }
00330
00331 ifc->ifc_buff = NULL;
00332
00333 return sr;
00334 }
00335
00336
00347 static int At91MciDiscover(MCIFC * ifc)
00348 {
00349 uint32_t sr;
00350 int tmo;
00351
00352
00353 At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00354 NutSleep(10);
00355
00356
00357 for (tmo = 100; --tmo;) {
00358 At91MciTxCmd(ifc, MCICMD_SEND_APP_CMD, 0);
00359 sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V);
00360 ifc->ifc_opcond = ifc->ifc_resp[0];
00361 if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00362 ifc->ifc_config |= MCIFLG_SDCARD;
00363 break;
00364 }
00365 }
00366
00367 if (tmo == 0) {
00368
00369 At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0);
00370 NutSleep(10);
00371
00372
00373 for (tmo = 100; --tmo;) {
00374 sr = At91MciTxCmd(ifc, MCICMD_SEND_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V);
00375 ifc->ifc_opcond = ifc->ifc_resp[0];
00376 if (ifc->ifc_resp[0] & MMCOP_NBUSY) {
00377 break;
00378 }
00379 }
00380 }
00381
00382 if (tmo == 0) {
00383
00384 return -1;
00385 }
00386
00387
00388 ifc->ifc_reladdr = 0;
00389 for (tmo = 500; --tmo;) {
00390 sr = At91MciTxCmd(ifc, MCICMD_ALL_SEND_CID, 0);
00391 memcpy(ifc->ifc_cid, ifc->ifc_resp, sizeof(ifc->ifc_cid));
00392 if (sr & MCI_RTOE) {
00393
00394 break;
00395 }
00396 if (ifc->ifc_config & MCIFLG_SDCARD) {
00397
00398 ifc->ifc_reladdr = 0;
00399 } else {
00400
00401 ifc->ifc_reladdr++;
00402 }
00403 At91MciTxCmd(ifc, MCICMD_SEND_RELATIVE_ADDR, ifc->ifc_reladdr << 16);
00404 if (ifc->ifc_config & MCIFLG_SDCARD) {
00405
00406 ifc->ifc_reladdr = ifc->ifc_resp[0] >> 16;
00407 }
00408 }
00409
00410
00411 outr(MCI_MR, MCI_PDCMODE | (2 << MCI_PWSDIV_LSB) | (16 << MCI_CLKDIV_LSB));
00412
00413 return ifc->ifc_reladdr ? 0 : -1;
00414 }
00415
00425 static int At91MciReadSingle(MCIFC * ifc, uint32_t blk, uint8_t * buf)
00426 {
00427 int rc = -1;
00428 uint32_t sr;
00429
00430
00431 NutEventWait(&mutex, 0);
00432
00433 sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00434 if ((sr & MCICMD_ERROR) == 0) {
00435 sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00436 if ((sr & MCICMD_ERROR) == 0) {
00437 ifc->ifc_buff = buf;
00438 sr = At91MciTxCmd(ifc, MCICMD_READ_SINGLE_BLOCK, blk * MMC_BLOCK_SIZE);
00439 if ((sr & MCICMD_ERROR) == 0) {
00440 rc = 0;
00441 }
00442 }
00443 At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00444 }
00445
00446
00447 NutEventPost(&mutex);
00448
00449 return rc;
00450 }
00451
00461 static int At91MciWriteSingle(MCIFC * ifc, uint32_t blk, CONST uint8_t * buf)
00462 {
00463 int rc = -1;
00464 uint32_t sr;
00465
00466
00467 NutEventWait(&mutex, 0);
00468
00469 sr = At91MciTxCmd(ifc, MCICMD_SELECT_CARD, ifc->ifc_reladdr << 16);
00470 if ((sr & MCICMD_ERROR) == 0) {
00471 sr = At91MciTxCmd(ifc, MCICMD_SET_BLOCKLEN, MMC_BLOCK_SIZE);
00472 if ((sr & MCICMD_ERROR) == 0) {
00473 ifc->ifc_buff = (uint8_t *)buf;
00474 sr = At91MciTxCmd(ifc, MCICMD_WRITE_BLOCK, blk * MMC_BLOCK_SIZE);
00475 if ((sr & MCICMD_ERROR) == 0) {
00476 rc = 0;
00477 }
00478 }
00479 At91MciTxCmd(ifc, MCICMD_DESELECT_CARD, 0);
00480 }
00481
00482
00483 NutEventPost(&mutex);
00484
00485 return rc;
00486 }
00487
00500 static int At91MciBlockRead(NUTFILE * nfp, void *buffer, int num)
00501 {
00502 MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00503 uint32_t blk = fcb->fcb_blknum;
00504 NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00505 MCIFC *ifc = (MCIFC *) dev->dev_icb;
00506 int rt;
00507
00508 if (buffer == 0) {
00509 buffer = fcb->fcb_blkbuf;
00510 }
00511 blk += fcb->fcb_part.part_sect_offs;
00512
00513 for (rt = 10; --rt >= 0;) {
00514 if (At91MciReadSingle(ifc, blk, buffer) == 0) {
00515 return 1;
00516 }
00517 At91MciReset(0);
00518 }
00519 return -1;
00520 }
00521
00534 static int At91MciBlockWrite(NUTFILE * nfp, CONST void *buffer, int num)
00535 {
00536 MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00537 uint32_t blk = fcb->fcb_blknum;
00538 NUTDEVICE *dev = (NUTDEVICE *) nfp->nf_dev;
00539 MCIFC *ifc = (MCIFC *) dev->dev_icb;
00540
00541 if (buffer == 0) {
00542 buffer = fcb->fcb_blkbuf;
00543 }
00544 blk += fcb->fcb_part.part_sect_offs;
00545
00546 if (At91MciWriteSingle(ifc, blk, buffer) == 0) {
00547 return 1;
00548 }
00549 return -1;
00550 }
00551
00560 static int At91MciUnmount(NUTFILE * nfp)
00561 {
00562 int rc = -1;
00563
00564 if (nfp) {
00565 MCIFCB *fcb = (MCIFCB *) nfp->nf_fcb;
00566
00567 if (fcb) {
00568 rc = fcb->fcb_fsdev->dev_ioctl(fcb->fcb_fsdev, FS_VOL_UNMOUNT, NULL);
00569 NutHeapFree(fcb);
00570 }
00571 NutHeapFree(nfp);
00572 }
00573 return rc;
00574 }
00575
00601 static NUTFILE *At91MciMount(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00602 {
00603 int partno = 0;
00604 int i;
00605 NUTDEVICE *fsdev;
00606 NUTFILE *nfp;
00607 MCIFCB *fcb;
00608 DOSPART *part;
00609 MCIFC *ifc = (MCIFC *) dev->dev_icb;
00610 FSCP_VOL_MOUNT mparm;
00611
00612 if (At91MciDiscover(ifc)) {
00613 errno = ENODEV;
00614 return NUTFILE_EOF;
00615 }
00616
00617
00618 if (*name) {
00619 partno = atoi(name);
00620 do {
00621 name++;
00622 } while (*name && *name != '/');
00623 if (*name == '/') {
00624 name++;
00625 }
00626 }
00627 #ifdef NUTDEBUG
00628 printf("['%s'-PART%d]", name, partno);
00629 #endif
00630
00631
00632
00633
00634
00635
00636
00637 for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) {
00638 if (*name == 0) {
00639 if (fsdev->dev_type == IFTYP_FS) {
00640 break;
00641 }
00642 } else if (strcmp(fsdev->dev_name, name) == 0) {
00643 break;
00644 }
00645 }
00646
00647 if (fsdev == 0) {
00648 #ifdef NUTDEBUG
00649 printf("[No FSDriver]");
00650 #endif
00651 errno = ENODEV;
00652 return NUTFILE_EOF;
00653 }
00654
00655 if ((fcb = NutHeapAllocClear(sizeof(MCIFCB))) == 0) {
00656 errno = ENOMEM;
00657 return NUTFILE_EOF;
00658 }
00659 fcb->fcb_fsdev = fsdev;
00660
00661
00662 NutEventPost(&mutex);
00663
00664
00665 if (At91MciReadSingle(ifc, 0, fcb->fcb_blkbuf)) {
00666 NutHeapFree(fcb);
00667 return NUTFILE_EOF;
00668 }
00669
00670 if (fcb->fcb_blkbuf[DOSPART_MAGICPOS] != 0x55 || fcb->fcb_blkbuf[DOSPART_MAGICPOS + 1] != 0xAA) {
00671 NutHeapFree(fcb);
00672 return NUTFILE_EOF;
00673 }
00674
00675
00676 if(fcb->fcb_blkbuf[DOSPART_TYPEPOS] == 'F' &&
00677 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 1] == 'A' &&
00678 fcb->fcb_blkbuf[DOSPART_TYPEPOS + 2] == 'T') {
00679
00680 fcb->fcb_part.part_type = PTYPE_FAT12;
00681 fcb->fcb_part.part_sect_offs = 0;
00682 fcb->fcb_part.part_sects = 65536;
00683 }
00684 else {
00685
00686 part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS];
00687 for (i = 1; i <= 4; i++) {
00688 if (partno) {
00689 if (i == partno) {
00690
00691 fcb->fcb_part = *part;
00692 break;
00693 }
00694 } else if (part->part_state & 0x80) {
00695
00696 fcb->fcb_part = *part;
00697 break;
00698 }
00699 part++;
00700 }
00701
00702 if (fcb->fcb_part.part_type == PTYPE_EMPTY) {
00703 NutHeapFree(fcb);
00704 return NUTFILE_EOF;
00705 }
00706 }
00707 if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) {
00708 NutHeapFree(fcb);
00709 errno = ENOMEM;
00710 return NUTFILE_EOF;
00711 }
00712 nfp->nf_next = 0;
00713 nfp->nf_dev = dev;
00714 nfp->nf_fcb = fcb;
00715
00716
00717
00718
00719 mparm.fscp_bmnt = nfp;
00720 mparm.fscp_part_type = fcb->fcb_part.part_type;
00721 if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) {
00722 At91MciUnmount(nfp);
00723 return NUTFILE_EOF;
00724 }
00725 return nfp;
00726 }
00727
00751 static int At91MciIOCtrl(NUTDEVICE * dev, int req, void *conf)
00752 {
00753 int rc = 0;
00754 MCIFC *ifc = (MCIFC *) dev->dev_icb;
00755
00756 switch (req) {
00757 case NUTBLKDEV_MEDIAAVAIL:
00758 *((int *) conf) = 1;
00759 break;
00760 case NUTBLKDEV_MEDIACHANGE:
00761 *((int *) conf) = 0;
00762 break;
00763 case NUTBLKDEV_INFO:
00764 {
00765 BLKPAR_INFO *par = (BLKPAR_INFO *) conf;
00766 MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00767
00768 par->par_nblks = fcb->fcb_part.part_sects;
00769 par->par_blksz = MMC_BLOCK_SIZE;
00770 par->par_blkbp = fcb->fcb_blkbuf;
00771 }
00772 break;
00773 case NUTBLKDEV_SEEK:
00774 {
00775 BLKPAR_SEEK *par = (BLKPAR_SEEK *) conf;
00776 MCIFCB *fcb = (MCIFCB *) par->par_nfp->nf_fcb;
00777
00778 fcb->fcb_blknum = par->par_blknum;
00779 }
00780 break;
00781 case MMCARD_GETOCR:
00782 *((uint32_t *) conf) = ifc->ifc_opcond;
00783 break;
00784 default:
00785 rc = -1;
00786 break;
00787 }
00788 return rc;
00789 }
00790
00791 static MCIFC mci0_info;
00792
00805 NUTDEVICE devAt91Mci0 = {
00806 0,
00807 {'M', 'C', 'I', '0', 0, 0, 0, 0, 0}
00808 ,
00809 0,
00810 0,
00811 0,
00812 &mci0_info,
00813 0,
00814 At91MciInit,
00815 At91MciIOCtrl,
00816 At91MciBlockRead,
00817 At91MciBlockWrite,
00818 At91MciMount,
00819 At91MciUnmount,
00820 0
00821 };
00822