diff options
author | Alagu Sankar <alagusankar@embwise.com> | 2010-09-21 08:55:59 +0530 |
---|---|---|
committer | Sudhakar Rajashekhara <sudhakar.raj@ti.com> | 2010-09-21 08:55:59 +0530 |
commit | abca1d3ba5805d32944388eb165ca73a5192dbe1 (patch) | |
tree | 35ab19c52a7d856a01c24482f162026e4fc218e6 | |
parent | f7da8ce3a9173815be28e8b5cd0c4703ef763e4f (diff) |
Multiblock Support for MMC
Added Multi-Block Read support for MMC. Modified existing multi-block write
to limit the maximum number of blocks per transfer. This feature is enabled
with CONFIG_MMC_MBLOCK option. A new member is added in the mmc structure
for the host controllers to specify the maximum number of blocks it supports.
If the feature is disabled all read/write transfers are single-block.
Signed-off-by: Alagu Sankar <alagusankar@embwise.com>
-rw-r--r-- | drivers/mmc/davinci_mmc.c | 3 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 161 | ||||
-rw-r--r-- | include/configs/da850evm.h | 1 | ||||
-rw-r--r-- | include/mmc.h | 3 |
4 files changed, 87 insertions, 81 deletions
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c index 2a3ef13e09..a28a597e70 100644 --- a/drivers/mmc/davinci_mmc.c +++ b/drivers/mmc/davinci_mmc.c @@ -397,6 +397,9 @@ int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host) mmc->voltages = host->voltages; mmc->host_caps = host->host_caps; +#ifdef CONFIG_MMC_MBLOCK + mmc->b_max = DAVINCI_MAX_BLOCKS; +#endif mmc_register(mmc); return 0; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b69ce152a8..346e6478e0 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -70,27 +70,12 @@ struct mmc *find_mmc_device(int dev_num) return NULL; } -static ulong -mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) +static int mmc_write_block(struct mmc *mmc, const char *src, uint blocknum, + uint blkcnt) { + int err; 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; @@ -98,42 +83,82 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; if (mmc->high_capacity) - cmd.cmdarg = start; + cmd.cmdarg = blocknum; else - cmd.cmdarg = start * blklen; + cmd.cmdarg = blocknum * mmc->write_bl_len; cmd.resp_type = MMC_RSP_R1; cmd.flags = 0; data.src = src; data.blocks = blkcnt; - data.blocksize = blklen; + data.blocksize = mmc->write_bl_len; data.flags = MMC_DATA_WRITE; err = mmc_send_cmd(mmc, &cmd, &data); - - if (err) { - printf("mmc write failed\n\r"); + if (err) 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); + err = mmc_send_cmd(mmc, &cmd, NULL); + } + + return err; +} + +static ulong +mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) +{ + int err; + int i; + struct mmc *mmc = find_mmc_device(dev_num); +#ifdef CONFIG_MMC_MBLOCK + uint b_max = mmc->b_max; +#else + uint b_max = 1; +#endif + + if (!mmc) + return 0; + + /* We always do full block reads from the card */ + err = mmc_set_blocklen(mmc, mmc->write_bl_len); + + if (err) { + return 0; + } + + for (i = blkcnt; i > 0; i -= b_max) { + uint blocks = (i > b_max) ? b_max : i; + + err = mmc_write_block(mmc, src, start, blocks); + if (err) { + printf("block write failed: %d\n", err); + return blkcnt - i; + } + start += blocks; + src += (mmc->write_bl_len * blocks); } return blkcnt; + } -int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) +static int +mmc_read_block(struct mmc *mmc, void *dst, uint blocknum, uint blkcnt) { + int err; struct mmc_cmd cmd; struct mmc_data data; - cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; + if (blkcnt > 1) + cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; + else + cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; if (mmc->high_capacity) cmd.cmdarg = blocknum; @@ -144,70 +169,37 @@ int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) cmd.flags = 0; data.dest = dst; - data.blocks = 1; + data.blocks = blkcnt; 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 = lldiv(src, mmc->read_bl_len); - int endblock = lldiv(src + size - 1, mmc->read_bl_len); - 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) + err = mmc_send_cmd(mmc, &cmd, &data); + 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); + if (blkcnt > 1) { + cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_RSP_R1b; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + } return err; } -static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) +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); +#ifdef CONFIG_MMC_MBLOCK + uint b_max = mmc->b_max; +#else + uint b_max = 1; +#endif if (!mmc) return 0; @@ -219,13 +211,16 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) return 0; } - for (i = start; i < start + blkcnt; i++, dst += mmc->read_bl_len) { - err = mmc_read_block(mmc, dst, i); + for (i = blkcnt; i > 0; i -= b_max) { + uint blocks = (i > b_max) ? b_max : i; + err = mmc_read_block(mmc, dst, start, blocks); if (err) { printf("block read failed: %d\n", err); - return i - start; + return blkcnt - i; } + start += blocks; + dst += (mmc->read_bl_len * blocks); } return blkcnt; @@ -836,6 +831,10 @@ int mmc_register(struct mmc *mmc) mmc->block_dev.block_read = mmc_bread; mmc->block_dev.block_write = mmc_bwrite; +#ifdef CONFIG_MMC_MBLOCK + if (mmc->b_max == 0) + mmc->b_max = 1; +#endif INIT_LIST_HEAD (&mmc->link); list_add_tail (&mmc->link, &mmc_devices); diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h index 83e98dff2e..79b0045116 100644 --- a/include/configs/da850evm.h +++ b/include/configs/da850evm.h @@ -162,6 +162,7 @@ #define CONFIG_MMC #define CONFIG_GENERIC_MMC #define CONFIG_DAVINCI_MMC +#define CONFIG_MMC_MBLOCK #ifdef CONFIG_MMC #define CONFIG_DOS_PARTITION diff --git a/include/mmc.h b/include/mmc.h index 2dc69abb68..1d9cabca2f 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -264,6 +264,9 @@ struct mmc { struct mmc_cmd *cmd, struct mmc_data *data); void (*set_ios)(struct mmc *mmc); int (*init)(struct mmc *mmc); +#ifdef CONFIG_MMC_MBLOCK + uint b_max; +#endif }; int mmc_register(struct mmc *mmc); |