123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- /*
- * Copyright 2008, Freescale Semiconductor, Inc
- * Andy Fleming
- *
- * Based vaguely on the Linux code
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
- #include <config.h>
- #include <common.h>
- #include <command.h>
- #include <mmc.h>
- #include <part.h>
- #include <malloc.h>
- #include <linux/list.h>
- #include <mmc.h>
- static struct list_head mmc_devices;
- static int cur_dev_num = -1;
- int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
- {
- return mmc->send_cmd(mmc, cmd, data);
- }
- int mmc_set_blocklen(struct mmc *mmc, int len)
- {
- struct mmc_cmd cmd;
- cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = len;
- cmd.flags = 0;
- return mmc_send_cmd(mmc, &cmd, NULL);
- }
- struct mmc *find_mmc_device(int dev_num)
- {
- struct mmc *m;
- struct list_head *entry;
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
- if (m->block_dev.dev == dev_num)
- return m;
- }
- printf("MMC Device %d not found\n", dev_num);
- return NULL;
- }
- static ulong
- mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
- {
- struct mmc_cmd cmd;
- struct mmc_data data;
- int err;
- int stoperr = 0;
- struct mmc *mmc = find_mmc_device(dev_num);
- int blklen;
- if (!mmc)
- return -1;
- blklen = mmc->write_bl_len;
- err = mmc_set_blocklen(mmc, mmc->write_bl_len);
- if (err) {
- printf("set write bl len failed\n\r");
- return err;
- }
- if (blkcnt > 1)
- cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
- else
- cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
- if (mmc->high_capacity)
- cmd.cmdarg = start;
- else
- cmd.cmdarg = start * blklen;
- cmd.resp_type = MMC_RSP_R1;
- cmd.flags = 0;
- data.src = src;
- data.blocks = blkcnt;
- data.blocksize = blklen;
- data.flags = MMC_DATA_WRITE;
- err = mmc_send_cmd(mmc, &cmd, &data);
- if (err) {
- printf("mmc write failed\n\r");
- return err;
- }
- if (blkcnt > 1) {
- cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
- cmd.cmdarg = 0;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.flags = 0;
- stoperr = mmc_send_cmd(mmc, &cmd, NULL);
- }
- return blkcnt;
- }
- int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum)
- {
- struct mmc_cmd cmd;
- struct mmc_data data;
- cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
- if (mmc->high_capacity)
- cmd.cmdarg = blocknum;
- else
- cmd.cmdarg = blocknum * mmc->read_bl_len;
- cmd.resp_type = MMC_RSP_R1;
- cmd.flags = 0;
- data.dest = dst;
- data.blocks = 1;
- data.blocksize = mmc->read_bl_len;
- data.flags = MMC_DATA_READ;
- return mmc_send_cmd(mmc, &cmd, &data);
- }
- int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size)
- {
- char *buffer;
- int i;
- int blklen = mmc->read_bl_len;
- int startblock = src / blklen;
- int endblock = (src + size - 1) / blklen;
- int err = 0;
- /* Make a buffer big enough to hold all the blocks we might read */
- buffer = malloc(blklen);
- if (!buffer) {
- printf("Could not allocate buffer for MMC read!\n");
- return -1;
- }
- /* We always do full block reads from the card */
- err = mmc_set_blocklen(mmc, mmc->read_bl_len);
- if (err)
- return err;
- for (i = startblock; i <= endblock; i++) {
- int segment_size;
- int offset;
- err = mmc_read_block(mmc, buffer, i);
- if (err)
- goto free_buffer;
- /*
- * The first block may not be aligned, so we
- * copy from the desired point in the block
- */
- offset = (src & (blklen - 1));
- segment_size = MIN(blklen - offset, size);
- memcpy(dst, buffer + offset, segment_size);
- dst += segment_size;
- src += segment_size;
- size -= segment_size;
- }
- free_buffer:
- free(buffer);
- return err;
- }
- static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
- {
- int err;
- int i;
- struct mmc *mmc = find_mmc_device(dev_num);
- if (!mmc)
- return 0;
- /* We always do full block reads from the card */
- err = mmc_set_blocklen(mmc, mmc->read_bl_len);
- if (err) {
- return 0;
- }
- for (i = start; i < start + blkcnt; i++, dst += mmc->read_bl_len) {
- err = mmc_read_block(mmc, dst, i);
- if (err) {
- printf("block read failed: %d\n", err);
- return i - start;
- }
- }
- return blkcnt;
- }
- int mmc_go_idle(struct mmc* mmc)
- {
- struct mmc_cmd cmd;
- int err;
- udelay(1000);
- cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
- cmd.cmdarg = 0;
- cmd.resp_type = MMC_RSP_NONE;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(2000);
- return 0;
- }
- int
- sd_send_op_cond(struct mmc *mmc)
- {
- int timeout = 1000;
- int err;
- struct mmc_cmd cmd;
- do {
- cmd.cmdidx = MMC_CMD_APP_CMD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = mmc->voltages;
- if (mmc->version == SD_VERSION_2)
- cmd.cmdarg |= OCR_HCS;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
- if (timeout <= 0)
- return UNUSABLE_ERR;
- if (mmc->version != SD_VERSION_2)
- mmc->version = SD_VERSION_1_0;
- mmc->ocr = ((uint *)(cmd.response))[0];
- mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
- mmc->rca = 0;
- return 0;
- }
- int mmc_send_op_cond(struct mmc *mmc)
- {
- int timeout = 1000;
- struct mmc_cmd cmd;
- int err;
- /* Some cards seem to need this */
- mmc_go_idle(mmc);
- do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = OCR_HCS | mmc->voltages;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
- if (timeout <= 0)
- return UNUSABLE_ERR;
- mmc->version = MMC_VERSION_UNKNOWN;
- mmc->ocr = ((uint *)(cmd.response))[0];
- mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
- mmc->rca = 0;
- return 0;
- }
- int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
- {
- struct mmc_cmd cmd;
- struct mmc_data data;
- int err;
- /* Get the Card Status Register */
- cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- data.dest = ext_csd;
- data.blocks = 1;
- data.blocksize = 512;
- data.flags = MMC_DATA_READ;
- err = mmc_send_cmd(mmc, &cmd, &data);
- return err;
- }
- int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
- {
- struct mmc_cmd cmd;
- cmd.cmdidx = MMC_CMD_SWITCH;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (index << 16) |
- (value << 8);
- cmd.flags = 0;
- return mmc_send_cmd(mmc, &cmd, NULL);
- }
- int mmc_change_freq(struct mmc *mmc)
- {
- char ext_csd[512];
- char cardtype;
- int err;
- mmc->card_caps = 0;
- /* Only version 4 supports high-speed */
- if (mmc->version < MMC_VERSION_4)
- return 0;
- mmc->card_caps |= MMC_MODE_4BIT;
- err = mmc_send_ext_csd(mmc, ext_csd);
- if (err)
- return err;
- if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
- mmc->high_capacity = 1;
- cardtype = ext_csd[196] & 0xf;
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
- if (err)
- return err;
- /* Now check to see that it worked */
- err = mmc_send_ext_csd(mmc, ext_csd);
- if (err)
- return err;
- /* No high-speed support */
- if (!ext_csd[185])
- return 0;
- /* High Speed is set, there are two types: 52MHz and 26MHz */
- if (cardtype & MMC_HS_52MHZ)
- mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
- else
- mmc->card_caps |= MMC_MODE_HS;
- return 0;
- }
- int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
- {
- struct mmc_cmd cmd;
- struct mmc_data data;
- /* Switch the frequency */
- cmd.cmdidx = SD_CMD_SWITCH_FUNC;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = (mode << 31) | 0xffffff;
- cmd.cmdarg &= ~(0xf << (group * 4));
- cmd.cmdarg |= value << (group * 4);
- cmd.flags = 0;
- data.dest = (char *)resp;
- data.blocksize = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- return mmc_send_cmd(mmc, &cmd, &data);
- }
- int sd_change_freq(struct mmc *mmc)
- {
- int err;
- struct mmc_cmd cmd;
- uint scr[2];
- uint switch_status[16];
- struct mmc_data data;
- int timeout;
- mmc->card_caps = 0;
- /* Read the SCR to find out if this card supports higher speeds */
- cmd.cmdidx = MMC_CMD_APP_CMD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- cmd.cmdidx = SD_CMD_APP_SEND_SCR;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- timeout = 3;
- retry_scr:
- data.dest = (char *)&scr;
- data.blocksize = 8;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- err = mmc_send_cmd(mmc, &cmd, &data);
- if (err) {
- if (timeout--)
- goto retry_scr;
- return err;
- }
- mmc->scr[0] = scr[0];
- mmc->scr[1] = scr[1];
- switch ((mmc->scr[0] >> 24) & 0xf) {
- case 0:
- mmc->version = SD_VERSION_1_0;
- break;
- case 1:
- mmc->version = SD_VERSION_1_10;
- break;
- case 2:
- mmc->version = SD_VERSION_2;
- break;
- default:
- mmc->version = SD_VERSION_1_0;
- break;
- }
- /* Version 1.0 doesn't support switching */
- if (mmc->version == SD_VERSION_1_0)
- return 0;
- timeout = 4;
- while (timeout--) {
- err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
- (u8 *)&switch_status);
- if (err)
- return err;
- /* The high-speed function is busy. Try again */
- if (!switch_status[7] & SD_HIGHSPEED_BUSY)
- break;
- }
- if (mmc->scr[0] & SD_DATA_4BIT)
- mmc->card_caps |= MMC_MODE_4BIT;
- /* If high-speed isn't supported, we return */
- if (!(switch_status[3] & SD_HIGHSPEED_SUPPORTED))
- return 0;
- err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status);
- if (err)
- return err;
- if ((switch_status[4] & 0x0f000000) == 0x01000000)
- mmc->card_caps |= MMC_MODE_HS;
- return 0;
- }
- /* frequency bases */
- /* divided by 10 to be nice to platforms without floating point */
- int fbase[] = {
- 10000,
- 100000,
- 1000000,
- 10000000,
- };
- /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
- * to platforms without floating point.
- */
- int multipliers[] = {
- 0, /* reserved */
- 10,
- 12,
- 13,
- 15,
- 20,
- 25,
- 30,
- 35,
- 40,
- 45,
- 50,
- 55,
- 60,
- 70,
- 80,
- };
- void mmc_set_ios(struct mmc *mmc)
- {
- mmc->set_ios(mmc);
- }
- void mmc_set_clock(struct mmc *mmc, uint clock)
- {
- if (clock > mmc->f_max)
- clock = mmc->f_max;
- if (clock < mmc->f_min)
- clock = mmc->f_min;
- mmc->clock = clock;
- mmc_set_ios(mmc);
- }
- void mmc_set_bus_width(struct mmc *mmc, uint width)
- {
- mmc->bus_width = width;
- mmc_set_ios(mmc);
- }
- int mmc_startup(struct mmc *mmc)
- {
- int err;
- uint mult, freq;
- u64 cmult, csize;
- struct mmc_cmd cmd;
- /* Put the Card in Identify Mode */
- cmd.cmdidx = MMC_CMD_ALL_SEND_CID;
- cmd.resp_type = MMC_RSP_R2;
- cmd.cmdarg = 0;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- memcpy(mmc->cid, cmd.response, 16);
- /*
- * For MMC cards, set the Relative Address.
- * For SD cards, get the Relatvie Address.
- * This also puts the cards into Standby State
- */
- cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
- cmd.cmdarg = mmc->rca << 16;
- cmd.resp_type = MMC_RSP_R6;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- if (IS_SD(mmc))
- mmc->rca = (((uint *)(cmd.response))[0] >> 16) & 0xffff;
- /* Get the Card-Specific Data */
- cmd.cmdidx = MMC_CMD_SEND_CSD;
- cmd.resp_type = MMC_RSP_R2;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- mmc->csd[0] = ((uint *)(cmd.response))[0];
- mmc->csd[1] = ((uint *)(cmd.response))[1];
- mmc->csd[2] = ((uint *)(cmd.response))[2];
- mmc->csd[3] = ((uint *)(cmd.response))[3];
- if (mmc->version == MMC_VERSION_UNKNOWN) {
- int version = (cmd.response[0] >> 2) & 0xf;
- switch (version) {
- case 0:
- mmc->version = MMC_VERSION_1_2;
- break;
- case 1:
- mmc->version = MMC_VERSION_1_4;
- break;
- case 2:
- mmc->version = MMC_VERSION_2_2;
- break;
- case 3:
- mmc->version = MMC_VERSION_3;
- break;
- case 4:
- mmc->version = MMC_VERSION_4;
- break;
- default:
- mmc->version = MMC_VERSION_1_2;
- break;
- }
- }
- /* divide frequency by 10, since the mults are 10x bigger */
- freq = fbase[(cmd.response[3] & 0x7)];
- mult = multipliers[((cmd.response[3] >> 3) & 0xf)];
- mmc->tran_speed = freq * mult;
- mmc->read_bl_len = 1 << ((((uint *)(cmd.response))[1] >> 16) & 0xf);
- if (IS_SD(mmc))
- mmc->write_bl_len = mmc->read_bl_len;
- else
- mmc->write_bl_len = 1 << ((((uint *)(cmd.response))[3] >> 22) & 0xf);
- if (mmc->high_capacity) {
- csize = (mmc->csd[1] & 0x3f) << 16
- | (mmc->csd[2] & 0xffff0000) >> 16;
- cmult = 8;
- } else {
- csize = (mmc->csd[1] & 0x3ff) << 2
- | (mmc->csd[2] & 0xc0000000) >> 30;
- cmult = (mmc->csd[2] & 0x00038000) >> 15;
- }
- mmc->capacity = (csize + 1) << (cmult + 2);
- mmc->capacity *= mmc->read_bl_len;
- if (mmc->read_bl_len > 512)
- mmc->read_bl_len = 512;
- if (mmc->write_bl_len > 512)
- mmc->write_bl_len = 512;
- /* Select the card, and put it into Transfer Mode */
- cmd.cmdidx = MMC_CMD_SELECT_CARD;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- if (IS_SD(mmc))
- err = sd_change_freq(mmc);
- else
- err = mmc_change_freq(mmc);
- if (err)
- return err;
- /* Restrict card's capabilities by what the host can do */
- mmc->card_caps &= mmc->host_caps;
- if (IS_SD(mmc)) {
- if (mmc->card_caps & MMC_MODE_4BIT) {
- cmd.cmdidx = MMC_CMD_APP_CMD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = mmc->rca << 16;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 2;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- mmc_set_bus_width(mmc, 4);
- }
- if (mmc->card_caps & MMC_MODE_HS)
- mmc_set_clock(mmc, 50000000);
- else
- mmc_set_clock(mmc, 25000000);
- } else {
- if (mmc->card_caps & MMC_MODE_4BIT) {
- /* Set the card to use 4 bit*/
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- EXT_CSD_BUS_WIDTH_4);
- if (err)
- return err;
- mmc_set_bus_width(mmc, 4);
- } else if (mmc->card_caps & MMC_MODE_8BIT) {
- /* Set the card to use 8 bit*/
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- EXT_CSD_BUS_WIDTH_8);
- if (err)
- return err;
- mmc_set_bus_width(mmc, 8);
- }
- if (mmc->card_caps & MMC_MODE_HS) {
- if (mmc->card_caps & MMC_MODE_HS_52MHz)
- mmc_set_clock(mmc, 52000000);
- else
- mmc_set_clock(mmc, 26000000);
- } else
- mmc_set_clock(mmc, 20000000);
- }
- /* fill in device description */
- mmc->block_dev.lun = 0;
- mmc->block_dev.type = 0;
- mmc->block_dev.blksz = mmc->read_bl_len;
- mmc->block_dev.lba = mmc->capacity/mmc->read_bl_len;
- sprintf(mmc->block_dev.vendor,"Man %02x%02x%02x Snr %02x%02x%02x%02x",
- mmc->cid[0], mmc->cid[1], mmc->cid[2],
- mmc->cid[9], mmc->cid[10], mmc->cid[11], mmc->cid[12]);
- sprintf(mmc->block_dev.product,"%c%c%c%c%c", mmc->cid[3],
- mmc->cid[4], mmc->cid[5], mmc->cid[6], mmc->cid[7]);
- sprintf(mmc->block_dev.revision,"%d.%d", mmc->cid[8] >> 4,
- mmc->cid[8] & 0xf);
- init_part(&mmc->block_dev);
- return 0;
- }
- int mmc_send_if_cond(struct mmc *mmc)
- {
- struct mmc_cmd cmd;
- int err;
- cmd.cmdidx = SD_CMD_SEND_IF_COND;
- /* We set the bit if the host supports voltages between 2.7 and 3.6 V */
- cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
- cmd.resp_type = MMC_RSP_R7;
- cmd.flags = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
- if ((((uint *)(cmd.response))[0] & 0xff) != 0xaa)
- return UNUSABLE_ERR;
- else
- mmc->version = SD_VERSION_2;
- return 0;
- }
- int mmc_register(struct mmc *mmc)
- {
- /* Setup the universal parts of the block interface just once */
- mmc->block_dev.if_type = IF_TYPE_MMC;
- mmc->block_dev.dev = cur_dev_num++;
- mmc->block_dev.removable = 1;
- mmc->block_dev.block_read = mmc_bread;
- mmc->block_dev.block_write = mmc_bwrite;
- INIT_LIST_HEAD (&mmc->link);
- list_add_tail (&mmc->link, &mmc_devices);
- return 0;
- }
- block_dev_desc_t *mmc_get_dev(int dev)
- {
- struct mmc *mmc = find_mmc_device(dev);
- return &mmc->block_dev;
- }
- int mmc_init(struct mmc *mmc)
- {
- int err;
- err = mmc->init(mmc);
- if (err)
- return err;
- /* Reset the Card */
- err = mmc_go_idle(mmc);
- if (err)
- return err;
- /* Test for SD version 2 */
- err = mmc_send_if_cond(mmc);
- /* If we got an error other than timeout, we bail */
- if (err && err != TIMEOUT)
- return err;
- /* Now try to get the SD card's operating condition */
- err = sd_send_op_cond(mmc);
- /* If the command timed out, we check for an MMC card */
- if (err == TIMEOUT) {
- err = mmc_send_op_cond(mmc);
- if (err) {
- printf("Card did not respond to voltage select!\n");
- return UNUSABLE_ERR;
- }
- }
- return mmc_startup(mmc);
- }
- /*
- * CPU and board-specific MMC initializations. Aliased function
- * signals caller to move on
- */
- static int __def_mmc_init(bd_t *bis)
- {
- return -1;
- }
- int cpu_mmc_init(bd_t *bis) __attribute((weak, alias("__def_mmc_init")));
- int board_mmc_init(bd_t *bis) __attribute((weak, alias("__def_mmc_init")));
- void print_mmc_devices(char separator)
- {
- struct mmc *m;
- struct list_head *entry;
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
- printf("%s: %d", m->name, m->block_dev.dev);
- if (entry->next != &mmc_devices)
- printf("%c ", separator);
- }
- printf("\n");
- }
- int mmc_initialize(bd_t *bis)
- {
- INIT_LIST_HEAD (&mmc_devices);
- cur_dev_num = 0;
- if (board_mmc_init(bis) < 0)
- cpu_mmc_init(bis);
- print_mmc_devices(',');
- return 0;
- }
|