/*! * \brief Read or verify a single block. * * \param ifc Specifies the hardware interface. * \param blk Block number to read or verify. * \param buf Data buffer. Receives the data or is verified against the * data being read from the card. * * \return 0 on success, -1 otherwise. */ static int At91MciReadSingle(MCIFC * ifc, u_long blk, u_char * buf) { int rc = -1; u_int sr; /* Gain mutex access. */ NutEventWait(&mutex, 0); #ifdef NUTDEBUG printf("[RB%lu]", blk); #endif sr = At91MciTxCmd(ifc, MCI_MAXLAT | MCI_RSPTYP_48 | MMCMD_SELECT_CARD, ifc->ifc_reladdr << 16); if ((sr & 0xC07F0000) == 0) { sr = At91MciTxCmd(ifc, MCI_MAXLAT | MCI_RSPTYP_48 | MMCMD_SET_BLOCKLEN, MMC_BLOCK_SIZE); if ((sr & 0xC07F0000) == 0) { ifc->ifc_buff = buf; sr = At91MciTxCmd(ifc, MCI_TRDIR | MCI_TRCMD_START | MCI_MAXLAT | MCI_RSPTYP_48 | MMCMD_READ_SINGLE_BLOCK, blk * MMC_BLOCK_SIZE); if ((sr & 0xC07F0000) == 0) { rc = 0; } } At91MciTxCmd(ifc, MMCMD_SELECT_CARD, 0); } /* Release mutex access. */ NutEventPost(&mutex); return rc; }
/*! * \brief Discover available cards. * * \param ifc Specifies the hardware interface. * * \return 0 on success, -1 otherwise. */ static int At91MciDiscover(MCIFC * ifc) { u_int sr; int tmo; /* Put all cards in idle state. */ #ifdef NUTDEBUG printf("\n[MciIdle]"); #endif outr(MCI_MR, MCI_PDCMODE | (3 << MCI_PWSDIV_LSB) | (47 << MCI_CLKDIV_LSB)); // 400kHz during identification At91MciTxCmd(ifc, MMCMD_GO_IDLE_STATE, 0); /* Poll operating conditions. */ #ifdef NUTDEBUG printf("\n[MciOpCond]"); #endif for (tmo = 1000; --tmo;) { sr = At91MciTxCmd(ifc, MCI_OPCMD | MCI_MAXLAT | MCI_RSPTYP_48 | MMCMD_SEND_OP_COND, ifc->ifc_opcond); if (sr & 0xC06B0000) { return -1; } if ((ifc->ifc_resp[0] & MMCOP_NBUSY) != 0) { break; } ifc->ifc_opcond = ifc->ifc_resp[0]; NutSleep(1); } if (tmo == 0) { #ifdef NUTDEBUG printf("[Failed]"); #endif return -1; } /* Discover cards. */ #ifdef NUTDEBUG printf("\n[MciDiscover]"); #endif ifc->ifc_reladdr = 0; for (tmo = 500; --tmo;) { sr = At91MciTxCmd(ifc, MCI_OPCMD | MCI_MAXLAT | MCI_RSPTYP_136 | MMCMD_ALL_SEND_CID, 0); if (sr & MCI_RTOE) { /* No more cards. */ break; } ifc->ifc_reladdr++; At91MciTxCmd(ifc, MCI_MAXLAT | MCI_RSPTYP_48 | MMCMD_SEND_RELATIVE_ADDR, ifc->ifc_reladdr << 16); } #ifdef NUTDEBUG printf("[%u Cards]", ifc->ifc_reladdr); #endif outr(MCI_MR, MCI_PDCMODE | (3 << MCI_PWSDIV_LSB) | (1 << MCI_CLKDIV_LSB)); // 10MHz @ 180/4 MHz return ifc->ifc_reladdr ? 0 : -1; }
/*! * \brief Discover available cards. * * Currently this has been tested for SanDisk SD Cards and several * MultiMedia Cards. It doesn't seem to work with RS-MMC, though. * * \param ifc Specifies the hardware interface. * * \return 0 on success, -1 otherwise. */ static int At91MciDiscover(MCIFC * ifc) { uint32_t sr; uint32_t clk = MCI_MMC_BITRATE; uint32_t opd = 0; int tmo; At91MciEnablePins(); /* Put all cards in idle state. */ At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE | MCI_SPCMD_INIT, 0); At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0); /* Poll SDC operating conditions. */ for (tmo = 1000; --tmo;) { sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_CMD, 0); if ((ifc->ifc_resp[0] & (1 << 8)) != 0 && (sr & MCICMD_IERROR) == 0) { sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_OP_COND, MMCARD_VRANGE); if ((sr & MCICMD_IERROR) == 0) { ifc->ifc_opcond = ifc->ifc_resp[0]; if (ifc->ifc_resp[0] & MMCOP_NBUSY) { ifc->ifc_config |= MCIFLG_SDCARD; break; } } } NutSleep(1); } if (tmo == 0) { /* No SDC. Put all cards back in idle state and try MMC. */ opd = MCI_OPDCMD; At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0); /* Poll MMC operating conditions. */ for (tmo = 100; --tmo;) { sr = At91MciTxCmd(ifc, MCICMD_SEND_OP_COND | opd, MMCARD_VRANGE); ifc->ifc_opcond = ifc->ifc_resp[0]; if (ifc->ifc_resp[0] & MMCOP_NBUSY) { break; } NutSleep(1); } } if (tmo == 0) { /* No valid card. */ At91MciDisablePins(); return -1; } /* Discover cards. */ ifc->ifc_reladdr = 0; for (tmo = 50; --tmo;) { sr = At91MciTxCmd(ifc, MCICMD_ALL_SEND_CID | opd, 0); memcpy(ifc->ifc_cid, ifc->ifc_resp, sizeof(ifc->ifc_cid)); if (sr & MCI_RTOE) { /* No more cards. */ break; } if (ifc->ifc_config & MCIFLG_SDCARD) { /* SD Card will send an address. */ ifc->ifc_reladdr = 0; } else { /* MultiMedia Card will receive an address. */ ifc->ifc_reladdr++; } At91MciTxCmd(ifc, MCICMD_SEND_RELATIVE_ADDR | opd, ifc->ifc_reladdr << 16); if (ifc->ifc_config & MCIFLG_SDCARD) { /* Store SD Card address. */ ifc->ifc_reladdr = ifc->ifc_resp[0] >> 16; /* SD Cards can run at higher clock rates. */ clk = MCI_SDC_BITRATE; } }
/*! * \brief Discover available cards. * * Currently this has been tested for SanDisk SD Cards and several * MultiMedia Cards. It doesn't seem to work with RS-MMC, though. * * \param ifc Specifies the hardware interface. * * \return 0 on success, -1 otherwise. */ static int At91MciDiscover(MCIFC * ifc) { uint32_t sr; int tmo; /* Put all cards in idle state. */ At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0); NutSleep(10); /* Poll SDC operating conditions. */ for (tmo = 100; --tmo;) { At91MciTxCmd(ifc, MCICMD_SEND_APP_CMD, 0); sr = At91MciTxCmd(ifc, MCICMD_SEND_APP_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V); ifc->ifc_opcond = ifc->ifc_resp[0]; if (ifc->ifc_resp[0] & MMCOP_NBUSY) { ifc->ifc_config |= MCIFLG_SDCARD; break; } } if (tmo == 0) { /* No SDC. Put all cards back in idle state and try MMC. */ At91MciTxCmd(ifc, MCICMD_GO_IDLE_STATE, 0); NutSleep(10); /* Poll MMC operating conditions. */ for (tmo = 100; --tmo;) { sr = At91MciTxCmd(ifc, MCICMD_SEND_OP_COND, MMCARD_32_33V | MMCARD_31_32V | MMCARD_30_31V); ifc->ifc_opcond = ifc->ifc_resp[0]; if (ifc->ifc_resp[0] & MMCOP_NBUSY) { break; } } } if (tmo == 0) { /* No valid card. */ return -1; } /* Discover cards. */ ifc->ifc_reladdr = 0; for (tmo = 500; --tmo;) { sr = At91MciTxCmd(ifc, MCICMD_ALL_SEND_CID, 0); memcpy(ifc->ifc_cid, ifc->ifc_resp, sizeof(ifc->ifc_cid)); if (sr & MCI_RTOE) { /* No more cards. */ break; } if (ifc->ifc_config & MCIFLG_SDCARD) { /* SD Card will send an address. */ ifc->ifc_reladdr = 0; } else { /* MultiMedia Card will receive an address. */ ifc->ifc_reladdr++; } At91MciTxCmd(ifc, MCICMD_SEND_RELATIVE_ADDR, ifc->ifc_reladdr << 16); if (ifc->ifc_config & MCIFLG_SDCARD) { /* Store SD Card address. */ ifc->ifc_reladdr = ifc->ifc_resp[0] >> 16; } }