diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mmc/mmc.c | 148 | 
1 files changed, 53 insertions, 95 deletions
| diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eb7bfb39e..6805b33f7 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -82,12 +82,9 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  {  	struct mmc_cmd cmd;  	struct mmc_data data; -	int blklen, err; - -	blklen = mmc->write_bl_len;  	if ((start + blkcnt) > mmc->block_dev.lba) { -		printf("MMC: block number 0x%lx exceeds max(0x%lx)", +		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",  			start + blkcnt, mmc->block_dev.lba);  		return 0;  	} @@ -100,21 +97,19 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  	if (mmc->high_capacity)  		cmd.cmdarg = start;  	else -		cmd.cmdarg = start * blklen; +		cmd.cmdarg = start * 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"); -		return err; +	if (mmc_send_cmd(mmc, &cmd, &data)) { +		printf("mmc write failed\n"); +		return 0;  	}  	if (blkcnt > 1) { @@ -122,10 +117,9 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  		cmd.cmdarg = 0;  		cmd.resp_type = MMC_RSP_R1b;  		cmd.flags = 0; -		err = mmc_send_cmd(mmc, &cmd, NULL); -		if (err) { -			printf("mmc fail to send stop cmd\n\r"); -			return err; +		if (mmc_send_cmd(mmc, &cmd, NULL)) { +			printf("mmc fail to send stop cmd\n"); +			return 0;  		}  	} @@ -135,18 +129,14 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  static ulong  mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)  { -	int err; -	struct mmc *mmc = find_mmc_device(dev_num);  	lbaint_t cur, blocks_todo = blkcnt; +	struct mmc *mmc = find_mmc_device(dev_num);  	if (!mmc) -		return -1; +		return 0; -	err = mmc_set_blocklen(mmc, mmc->write_bl_len); -	if (err) { -		printf("set write bl len failed\n\r"); -		return err; -	} +	if (mmc_set_blocklen(mmc, mmc->write_bl_len)) +		return 0;  	do {  		/* @@ -155,7 +145,7 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)  		 */  		cur = (blocks_todo > 65535) ? 65535 : blocks_todo;  		if(mmc_write_blocks(mmc, start, cur, src) != cur) -			return -1; +			return 0;  		blocks_todo -= cur;  		start += cur;  		src += cur * mmc->write_bl_len; @@ -164,110 +154,78 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)  	return blkcnt;  } -int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) +int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)  {  	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; +		cmd.cmdarg = start;  	else -		cmd.cmdarg = blocknum * mmc->read_bl_len; +		cmd.cmdarg = start * mmc->read_bl_len;  	cmd.resp_type = MMC_RSP_R1;  	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) -		goto free_buffer; - -	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); +	if (mmc_send_cmd(mmc, &cmd, &data)) +		return 0; -		dst += segment_size; -		src += segment_size; -		size -= segment_size; +	if (blkcnt > 1) { +		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; +		cmd.cmdarg = 0; +		cmd.resp_type = MMC_RSP_R1b; +		cmd.flags = 0; +		if (mmc_send_cmd(mmc, &cmd, NULL)) { +			printf("mmc fail to send stop cmd\n"); +			return 0; +		}  	} -free_buffer: -	free(buffer); - -	return err; +	return blkcnt;  }  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); +	lbaint_t cur, blocks_todo = blkcnt; +	if (blkcnt == 0) +		return 0; + +	struct mmc *mmc = find_mmc_device(dev_num);  	if (!mmc)  		return 0;  	if ((start + blkcnt) > mmc->block_dev.lba) { -		printf("MMC: block number 0x%lx exceeds max(0x%lx)", +		printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",  			start + blkcnt, mmc->block_dev.lba);  		return 0;  	} -	/* We always do full block reads from the card */ -	err = mmc_set_blocklen(mmc, mmc->read_bl_len); -	if (err) { +	if (mmc_set_blocklen(mmc, mmc->read_bl_len))  		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; -		} -	} +	do { +		/* +		 * The 65535 constraint comes from some hardware has +		 * only 16 bit width block number counter +		 */ +		cur = (blocks_todo > 65535) ? 65535 : blocks_todo; +		if(mmc_read_blocks(mmc, dst, start, cur) != cur) +			return 0; +		blocks_todo -= cur; +		start += cur; +		dst += cur * mmc->read_bl_len; +	} while (blocks_todo > 0);  	return blkcnt;  } |