summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlagu Sankar <alagusankar@embwise.com>2010-09-21 08:55:59 +0530
committerSudhakar Rajashekhara <sudhakar.raj@ti.com>2010-09-21 08:55:59 +0530
commitabca1d3ba5805d32944388eb165ca73a5192dbe1 (patch)
tree35ab19c52a7d856a01c24482f162026e4fc218e6
parentf7da8ce3a9173815be28e8b5cd0c4703ef763e4f (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.c3
-rw-r--r--drivers/mmc/mmc.c161
-rw-r--r--include/configs/da850evm.h1
-rw-r--r--include/mmc.h3
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);