/*!
 * \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;
        }
    }
예제 #4
0
/*!
 * \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;
        }
    }