diff options
| -rw-r--r-- | common/spl/spl_mmc.c | 17 | ||||
| -rw-r--r-- | drivers/mmc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/mmc/dw_mmc.c | 9 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 205 | ||||
| -rw-r--r-- | drivers/mmc/mmc_private.h | 45 | ||||
| -rw-r--r-- | drivers/mmc/mmc_write.c | 179 | ||||
| -rw-r--r-- | drivers/mmc/omap_hsmmc.c | 41 | ||||
| -rw-r--r-- | drivers/mmc/s5p_sdhci.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/sdhci.c | 18 | ||||
| -rw-r--r-- | include/common.h | 4 | ||||
| -rw-r--r-- | include/mmc.h | 4 | ||||
| -rw-r--r-- | include/sdhci.h | 3 | 
12 files changed, 336 insertions, 195 deletions
| diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index f27b4c277..fc2f2260f 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -9,7 +9,6 @@  #include <common.h>  #include <spl.h>  #include <asm/u-boot.h> -#include <asm/utils.h>  #include <mmc.h>  #include <fat.h>  #include <version.h> @@ -45,8 +44,10 @@ static int mmc_load_image_raw(struct mmc *mmc, unsigned long sector)  					(void *)spl_image.load_addr);  end: +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  	if (err == 0)  		printf("spl: mmc blk read err - %lu\n", err); +#endif  	return (err == 0);  } @@ -58,7 +59,9 @@ static int mmc_load_image_raw_os(struct mmc *mmc)  				       CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR,  				       CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS,  				       (void *)CONFIG_SYS_SPL_ARGS_ADDR)) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  		printf("mmc args blk read error\n"); +#endif  		return -1;  	} @@ -84,9 +87,11 @@ static int mmc_load_image_fat(struct mmc *mmc, const char *filename)  	err = file_fat_read(filename, (u8 *)spl_image.load_addr, 0);  end: +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  	if (err <= 0)  		printf("spl: error reading image %s, err - %d\n",  		       filename, err); +#endif  	return (err <= 0);  } @@ -99,8 +104,10 @@ static int mmc_load_image_fat_os(struct mmc *mmc)  	err = file_fat_read(CONFIG_SPL_FAT_LOAD_ARGS_NAME,  			    (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0);  	if (err <= 0) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  		printf("spl: error reading image %s, err - %d\n",  		       CONFIG_SPL_FAT_LOAD_ARGS_NAME, err); +#endif  		return -1;  	} @@ -120,13 +127,17 @@ void spl_mmc_load_image(void)  	/* We register only one device. So, the dev id is always 0 */  	mmc = find_mmc_device(0);  	if (!mmc) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  		puts("spl: mmc device not found!!\n"); +#endif  		hang();  	}  	err = mmc_init(mmc);  	if (err) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  		printf("spl: mmc init failed: err - %d\n", err); +#endif  		hang();  	} @@ -145,7 +156,9 @@ void spl_mmc_load_image(void)  		err = fat_register_device(&mmc->block_dev,  					  CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION);  		if (err) { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  			printf("spl: fat register err - %d\n", err); +#endif  			hang();  		} @@ -155,7 +168,9 @@ void spl_mmc_load_image(void)  		err = mmc_load_image_fat(mmc, CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME);  #endif  	} else { +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT  		puts("spl: wrong MMC boot mode\n"); +#endif  		hang();  	} diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index bedf833f7..06280d1fa 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -34,6 +34,8 @@ COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o  COBJS-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o  ifdef CONFIG_SPL_BUILD  COBJS-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o +else +COBJS-$(CONFIG_GENERIC_MMC) += mmc_write.o  endif  COBJS	:= $(COBJS-y) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index a82ee17a2..9a803a02d 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -41,12 +41,11 @@ static void dwmci_set_idma_desc(struct dwmci_idmac *idmac,  }  static void dwmci_prepare_data(struct dwmci_host *host, -		struct mmc_data *data) +		struct mmc_data *data, struct dwmci_idmac *cur_idmac)  {  	unsigned long ctrl;  	unsigned int i = 0, flags, cnt, blk_cnt;  	ulong data_start, data_end, start_addr; -	ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data->blocks);  	blk_cnt = data->blocks; @@ -73,7 +72,7 @@ static void dwmci_prepare_data(struct dwmci_host *host,  		dwmci_set_idma_desc(cur_idmac, flags, cnt,  				start_addr + (i * PAGE_SIZE)); -		if(blk_cnt < 8) +		if (blk_cnt <= 8)  			break;  		blk_cnt -= 8;  		cur_idmac++; @@ -111,6 +110,8 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  		struct mmc_data *data)  {  	struct dwmci_host *host = (struct dwmci_host *)mmc->priv; +	ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, +				 data ? DIV_ROUND_UP(data->blocks, 8) : 0);  	int flags = 0, i;  	unsigned int timeout = 100000;  	u32 retry = 10000; @@ -127,7 +128,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);  	if (data) -		dwmci_prepare_data(host, data); +		dwmci_prepare_data(host, data, cur_idmac);  	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 55026759e..84dae4d8b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -15,6 +15,7 @@  #include <malloc.h>  #include <linux/list.h>  #include <div64.h> +#include "mmc_private.h"  /* Set block count limit because of 16 bit register limit on some hardware*/  #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT @@ -52,14 +53,10 @@ int __board_mmc_getcd(struct mmc *mmc) {  int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,  	alias("__board_mmc_getcd"))); -static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, -			struct mmc_data *data) +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  { -	struct mmc_data backup;  	int ret; -	memset(&backup, 0, sizeof(backup)); -  #ifdef CONFIG_MMC_TRACE  	int i;  	u8 *ptr; @@ -114,7 +111,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  	return ret;  } -static int mmc_send_status(struct mmc *mmc, int timeout) +int mmc_send_status(struct mmc *mmc, int timeout)  {  	struct mmc_cmd cmd;  	int err, retries = 5; @@ -135,8 +132,10 @@ static int mmc_send_status(struct mmc *mmc, int timeout)  			     MMC_STATE_PRG)  				break;  			else if (cmd.response[0] & MMC_STATUS_MASK) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  				printf("Status Error: 0x%08X\n",  					cmd.response[0]); +#endif  				return COMM_ERR;  			}  		} else if (--retries < 0) @@ -151,14 +150,16 @@ static int mmc_send_status(struct mmc *mmc, int timeout)  	printf("CURR STATE:%d\n", status);  #endif  	if (timeout <= 0) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  		printf("Timeout waiting card ready\n"); +#endif  		return TIMEOUT;  	}  	return 0;  } -static int mmc_set_blocklen(struct mmc *mmc, int len) +int mmc_set_blocklen(struct mmc *mmc, int len)  {  	struct mmc_cmd cmd; @@ -181,179 +182,13 @@ struct mmc *find_mmc_device(int dev_num)  			return m;  	} +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  	printf("MMC Device %d not found\n", dev_num); +#endif  	return NULL;  } -static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) -{ -	struct mmc_cmd cmd; -	ulong end; -	int err, start_cmd, end_cmd; - -	if (mmc->high_capacity) -		end = start + blkcnt - 1; -	else { -		end = (start + blkcnt - 1) * mmc->write_bl_len; -		start *= mmc->write_bl_len; -	} - -	if (IS_SD(mmc)) { -		start_cmd = SD_CMD_ERASE_WR_BLK_START; -		end_cmd = SD_CMD_ERASE_WR_BLK_END; -	} else { -		start_cmd = MMC_CMD_ERASE_GROUP_START; -		end_cmd = MMC_CMD_ERASE_GROUP_END; -	} - -	cmd.cmdidx = start_cmd; -	cmd.cmdarg = start; -	cmd.resp_type = MMC_RSP_R1; - -	err = mmc_send_cmd(mmc, &cmd, NULL); -	if (err) -		goto err_out; - -	cmd.cmdidx = end_cmd; -	cmd.cmdarg = end; - -	err = mmc_send_cmd(mmc, &cmd, NULL); -	if (err) -		goto err_out; - -	cmd.cmdidx = MMC_CMD_ERASE; -	cmd.cmdarg = SECURE_ERASE; -	cmd.resp_type = MMC_RSP_R1b; - -	err = mmc_send_cmd(mmc, &cmd, NULL); -	if (err) -		goto err_out; - -	return 0; - -err_out: -	puts("mmc erase failed\n"); -	return err; -} - -static unsigned long -mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) -{ -	int err = 0; -	struct mmc *mmc = find_mmc_device(dev_num); -	lbaint_t blk = 0, blk_r = 0; -	int timeout = 1000; - -	if (!mmc) -		return -1; - -	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) -		printf("\n\nCaution! Your devices Erase group is 0x%x\n" -		       "The erase range would be change to " -		       "0x" LBAF "~0x" LBAF "\n\n", -		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), -		       ((start + blkcnt + mmc->erase_grp_size) -		       & ~(mmc->erase_grp_size - 1)) - 1); - -	while (blk < blkcnt) { -		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? -			mmc->erase_grp_size : (blkcnt - blk); -		err = mmc_erase_t(mmc, start + blk, blk_r); -		if (err) -			break; - -		blk += blk_r; - -		/* Waiting for the ready status */ -		if (mmc_send_status(mmc, timeout)) -			return 0; -	} - -	return blk; -} - -static ulong -mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src) -{ -	struct mmc_cmd cmd; -	struct mmc_data data; -	int timeout = 1000; - -	if ((start + blkcnt) > mmc->block_dev.lba) { -		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", -			start + blkcnt, mmc->block_dev.lba); -		return 0; -	} - -	if (blkcnt == 0) -		return 0; -	else if (blkcnt == 1) -		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; -	else -		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; - -	if (mmc->high_capacity) -		cmd.cmdarg = start; -	else -		cmd.cmdarg = start * mmc->write_bl_len; - -	cmd.resp_type = MMC_RSP_R1; - -	data.src = src; -	data.blocks = blkcnt; -	data.blocksize = mmc->write_bl_len; -	data.flags = MMC_DATA_WRITE; - -	if (mmc_send_cmd(mmc, &cmd, &data)) { -		printf("mmc write failed\n"); -		return 0; -	} - -	/* SPI multiblock writes terminate using a special -	 * token, not a STOP_TRANSMISSION request. -	 */ -	if (!mmc_host_is_spi(mmc) && blkcnt > 1) { -		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; -		cmd.cmdarg = 0; -		cmd.resp_type = MMC_RSP_R1b; -		if (mmc_send_cmd(mmc, &cmd, NULL)) { -			printf("mmc fail to send stop cmd\n"); -			return 0; -		} -	} - -	/* Waiting for the ready status */ -	if (mmc_send_status(mmc, timeout)) -		return 0; - -	return blkcnt; -} - -static ulong -mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src) -{ -	lbaint_t cur, blocks_todo = blkcnt; - -	struct mmc *mmc = find_mmc_device(dev_num); -	if (!mmc) -		return 0; - -	if (mmc_set_blocklen(mmc, mmc->write_bl_len)) -		return 0; - -	do { -		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo; -		if(mmc_write_blocks(mmc, start, cur, src) != cur) -			return 0; -		blocks_todo -= cur; -		start += cur; -		src += cur * mmc->write_bl_len; -	} while (blocks_todo > 0); - -	return blkcnt; -} -  static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,  			   lbaint_t blkcnt)  { @@ -385,7 +220,9 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,  		cmd.cmdarg = 0;  		cmd.resp_type = MMC_RSP_R1b;  		if (mmc_send_cmd(mmc, &cmd, NULL)) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  			printf("mmc fail to send stop cmd\n"); +#endif  			return 0;  		}  	} @@ -405,8 +242,10 @@ static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)  		return 0;  	if ((start + blkcnt) > mmc->block_dev.lba) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",  			start + blkcnt, mmc->block_dev.lba); +#endif  		return 0;  	} @@ -1268,6 +1107,7 @@ static int mmc_startup(struct mmc *mmc)  	mmc->block_dev.blksz = mmc->read_bl_len;  	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);  	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",  		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),  		(mmc->cid[3] >> 16) & 0xffff); @@ -1277,6 +1117,11 @@ static int mmc_startup(struct mmc *mmc)  		(mmc->cid[2] >> 24) & 0xff);  	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,  		(mmc->cid[2] >> 16) & 0xf); +#else +	mmc->block_dev.vendor[0] = 0; +	mmc->block_dev.product[0] = 0; +	mmc->block_dev.revision[0] = 0; +#endif  #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)  	init_part(&mmc->block_dev);  #endif @@ -1343,7 +1188,9 @@ int mmc_start_init(struct mmc *mmc)  	if (mmc_getcd(mmc) == 0) {  		mmc->has_init = 0; +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  		printf("MMC: no card present\n"); +#endif  		return NO_CARD_ERR;  	} @@ -1378,7 +1225,9 @@ int mmc_start_init(struct mmc *mmc)  		err = mmc_send_op_cond(mmc);  		if (err && err != IN_PROGRESS) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)  			printf("Card did not respond to voltage select!\n"); +#endif  			return UNUSABLE_ERR;  		}  	} @@ -1434,6 +1283,8 @@ static int __def_mmc_init(bd_t *bis)  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"))); +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +  void print_mmc_devices(char separator)  {  	struct mmc *m; @@ -1451,6 +1302,10 @@ void print_mmc_devices(char separator)  	printf("\n");  } +#else +void print_mmc_devices(char separator) { } +#endif +  int get_mmc_num(void)  {  	return cur_dev_num; diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h new file mode 100644 index 000000000..16dcf9ff6 --- /dev/null +++ b/drivers/mmc/mmc_private.h @@ -0,0 +1,45 @@ +/* + * Copyright 2008,2010 Freescale Semiconductor, Inc + * Andy Fleming + * + * Based (loosely) on the Linux code + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#ifndef _MMC_PRIVATE_H_ +#define _MMC_PRIVATE_H_ + +#include <mmc.h> + +extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, +			struct mmc_data *data); +extern int mmc_send_status(struct mmc *mmc, int timeout); +extern int mmc_set_blocklen(struct mmc *mmc, int len); + +#ifndef CONFIG_SPL_BUILD + +extern unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt); + +extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, +		const void *src); + +#else /* CONFIG_SPL_BUILD */ + +/* SPL will never write or erase, declare dummies to reduce code size. */ + +static inline unsigned long mmc_berase(int dev_num, lbaint_t start, +		lbaint_t blkcnt) +{ +	return 0; +} + +static inline ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, +		const void *src) +{ +	return 0; +} + +#endif /* CONFIG_SPL_BUILD */ + +#endif /* _MMC_PRIVATE_H_ */ diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c new file mode 100644 index 000000000..aa2fdefa7 --- /dev/null +++ b/drivers/mmc/mmc_write.c @@ -0,0 +1,179 @@ +/* + * Copyright 2008, Freescale Semiconductor, Inc + * Andy Fleming + * + * Based vaguely on the Linux code + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <part.h> +#include "mmc_private.h" + +static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) +{ +	struct mmc_cmd cmd; +	ulong end; +	int err, start_cmd, end_cmd; + +	if (mmc->high_capacity) { +		end = start + blkcnt - 1; +	} else { +		end = (start + blkcnt - 1) * mmc->write_bl_len; +		start *= mmc->write_bl_len; +	} + +	if (IS_SD(mmc)) { +		start_cmd = SD_CMD_ERASE_WR_BLK_START; +		end_cmd = SD_CMD_ERASE_WR_BLK_END; +	} else { +		start_cmd = MMC_CMD_ERASE_GROUP_START; +		end_cmd = MMC_CMD_ERASE_GROUP_END; +	} + +	cmd.cmdidx = start_cmd; +	cmd.cmdarg = start; +	cmd.resp_type = MMC_RSP_R1; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) +		goto err_out; + +	cmd.cmdidx = end_cmd; +	cmd.cmdarg = end; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) +		goto err_out; + +	cmd.cmdidx = MMC_CMD_ERASE; +	cmd.cmdarg = SECURE_ERASE; +	cmd.resp_type = MMC_RSP_R1b; + +	err = mmc_send_cmd(mmc, &cmd, NULL); +	if (err) +		goto err_out; + +	return 0; + +err_out: +	puts("mmc erase failed\n"); +	return err; +} + +unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) +{ +	int err = 0; +	struct mmc *mmc = find_mmc_device(dev_num); +	lbaint_t blk = 0, blk_r = 0; +	int timeout = 1000; + +	if (!mmc) +		return -1; + +	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) +		printf("\n\nCaution! Your devices Erase group is 0x%x\n" +		       "The erase range would be change to " +		       "0x" LBAF "~0x" LBAF "\n\n", +		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), +		       ((start + blkcnt + mmc->erase_grp_size) +		       & ~(mmc->erase_grp_size - 1)) - 1); + +	while (blk < blkcnt) { +		blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ? +			mmc->erase_grp_size : (blkcnt - blk); +		err = mmc_erase_t(mmc, start + blk, blk_r); +		if (err) +			break; + +		blk += blk_r; + +		/* Waiting for the ready status */ +		if (mmc_send_status(mmc, timeout)) +			return 0; +	} + +	return blk; +} + +static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, +		lbaint_t blkcnt, const void *src) +{ +	struct mmc_cmd cmd; +	struct mmc_data data; +	int timeout = 1000; + +	if ((start + blkcnt) > mmc->block_dev.lba) { +		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", +		       start + blkcnt, mmc->block_dev.lba); +		return 0; +	} + +	if (blkcnt == 0) +		return 0; +	else if (blkcnt == 1) +		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; +	else +		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; + +	if (mmc->high_capacity) +		cmd.cmdarg = start; +	else +		cmd.cmdarg = start * mmc->write_bl_len; + +	cmd.resp_type = MMC_RSP_R1; + +	data.src = src; +	data.blocks = blkcnt; +	data.blocksize = mmc->write_bl_len; +	data.flags = MMC_DATA_WRITE; + +	if (mmc_send_cmd(mmc, &cmd, &data)) { +		printf("mmc write failed\n"); +		return 0; +	} + +	/* SPI multiblock writes terminate using a special +	 * token, not a STOP_TRANSMISSION request. +	 */ +	if (!mmc_host_is_spi(mmc) && blkcnt > 1) { +		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; +		cmd.cmdarg = 0; +		cmd.resp_type = MMC_RSP_R1b; +		if (mmc_send_cmd(mmc, &cmd, NULL)) { +			printf("mmc fail to send stop cmd\n"); +			return 0; +		} +	} + +	/* Waiting for the ready status */ +	if (mmc_send_status(mmc, timeout)) +		return 0; + +	return blkcnt; +} + +ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src) +{ +	lbaint_t cur, blocks_todo = blkcnt; + +	struct mmc *mmc = find_mmc_device(dev_num); +	if (!mmc) +		return 0; + +	if (mmc_set_blocklen(mmc, mmc->write_bl_len)) +		return 0; + +	do { +		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo; +		if (mmc_write_blocks(mmc, start, cur, src) != cur) +			return 0; +		blocks_todo -= cur; +		start += cur; +		src += cur * mmc->write_bl_len; +	} while (blocks_todo > 0); + +	return blkcnt; +} diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 975b2c5ba..d3a8b5303 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -288,6 +288,30 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)  	mmc_reg_out(&mmc_base->sysctl, bit, bit); +	/* +	 * CMD(DAT) lines reset procedures are slightly different +	 * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx). +	 * According to OMAP3 TRM: +	 * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it +	 * returns to 0x0. +	 * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset +	 * procedure steps must be as follows: +	 * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in +	 *    MMCHS_SYSCTL register (SD_SYSCTL for AM335x). +	 * 2. Poll the SRC(SRD) bit until it is set to 0x1. +	 * 3. Wait until the SRC (SRD) bit returns to 0x0 +	 *    (reset procedure is completed). +	 */ +#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ +	defined(CONFIG_AM33XX) +	if (!(readl(&mmc_base->sysctl) & bit)) { +		start = get_timer(0); +		while (!(readl(&mmc_base->sysctl) & bit)) { +			if (get_timer(0) - start > MAX_RETRY_MS) +				return; +		} +	} +#endif  	start = get_timer(0);  	while ((readl(&mmc_base->sysctl) & bit) != 0) {  		if (get_timer(0) - start > MAX_RETRY_MS) { @@ -376,6 +400,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,  	}  	writel(cmd->cmdarg, &mmc_base->arg); +	udelay(20);		/* To fix "No status update" error on eMMC */  	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);  	start = get_timer(0); @@ -480,7 +505,7 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,  	unsigned int count;  	/* -	 * Start Polled Read +	 * Start Polled Write  	 */  	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;  	count /= 4; @@ -586,6 +611,8 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,  {  	struct mmc *mmc = &hsmmc_dev[dev_index];  	struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index]; +	uint host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS | +			     MMC_MODE_HC;  	sprintf(mmc->name, "OMAP SD/MMC");  	mmc->send_cmd = mmc_send_cmd; @@ -600,11 +627,20 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,  #ifdef OMAP_HSMMC2_BASE  	case 1:  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; +#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ +     defined(CONFIG_DRA7XX)) && defined(CONFIG_HSMMC2_8BIT) +		/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */ +		host_caps_val |= MMC_MODE_8BIT; +#endif  		break;  #endif  #ifdef OMAP_HSMMC3_BASE  	case 2:  		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE; +#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT) +		/* Enable 8-bit interface for eMMC on DRA7XX */ +		host_caps_val |= MMC_MODE_8BIT; +#endif  		break;  #endif  	default: @@ -620,8 +656,7 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,  		mmc->getwp = omap_mmc_getwp;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; -	mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS | -				MMC_MODE_HC) & ~host_caps_mask; +	mmc->host_caps = host_caps_val & ~host_caps_mask;  	mmc->f_min = 400000; diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 7f89403b4..40ff8739b 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -72,7 +72,7 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)  	host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |  		SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | -		SDHCI_QUIRK_WAIT_SEND_CMD; +		SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8;  	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;  	host->version = sdhci_readw(host, SDHCI_HOST_VERSION); @@ -81,6 +81,8 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)  	host->index = index;  	host->host_caps = MMC_MODE_HC; +	if (bus_width == 8) +		host->host_caps |= MMC_MODE_8BIT;  	return add_sdhci(host, 52000000, 400000);  } diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 42619916e..dfb2eeeb4 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -68,10 +68,9 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,  	unsigned int stat, rdy, mask, timeout, block = 0;  #ifdef CONFIG_MMC_SDMA  	unsigned char ctrl; -	ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); +	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);  	ctrl &= ~SDHCI_CTRL_DMA_MASK; -	ctrl |= SDHCI_CTRL_SDMA; -	sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL); +	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);  #endif  	timeout = 1000000; @@ -254,7 +253,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)  	if (clock == 0)  		return 0; -	if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { +	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {  		/* Version 3.00 divisors must be a multiple of 2. */  		if (mmc->f_max <= clock)  			div = 1; @@ -347,10 +346,11 @@ void sdhci_set_ios(struct mmc *mmc)  	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);  	if (mmc->bus_width == 8) {  		ctrl &= ~SDHCI_CTRL_4BITBUS; -		if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) +		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) || +				(host->quirks & SDHCI_QUIRK_USE_WIDE8))  			ctrl |= SDHCI_CTRL_8BITBUS;  	} else { -		if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) +		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)  			ctrl &= ~SDHCI_CTRL_8BITBUS;  		if (mmc->bus_width == 4)  			ctrl |= SDHCI_CTRL_4BITBUS; @@ -437,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)  	if (max_clk)  		mmc->f_max = max_clk;  	else { -		if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) +		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)  			mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)  				>> SDHCI_CLOCK_BASE_SHIFT;  		else @@ -452,7 +452,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)  	if (min_clk)  		mmc->f_min = min_clk;  	else { -		if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) +		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)  			mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300;  		else  			mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200; @@ -470,7 +470,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)  		mmc->voltages |= host->voltages;  	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; -	if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { +	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {  		if (caps & SDHCI_CAN_DO_8BIT)  			mmc->host_caps |= MMC_MODE_8BIT;  	} diff --git a/include/common.h b/include/common.h index 6aa239822..0d40fab04 100644 --- a/include/common.h +++ b/include/common.h @@ -1015,10 +1015,10 @@ static inline phys_addr_t map_to_sysmem(void *ptr)   * of a function scoped static buffer.  It can not be used to create a cache   * line aligned global buffer.   */ -#define PAD_COUNT(s, pad) ((s - 1) / pad + 1) +#define PAD_COUNT(s, pad) (((s) - 1) / (pad) + 1)  #define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad)  #define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad)		\ -	char __##name[ROUND(PAD_SIZE(size * sizeof(type), pad), align)  \ +	char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align)  \  		      + (align - 1)];					\  									\  	type *name = (type *) ALIGN((uintptr_t)__##name, align) diff --git a/include/mmc.h b/include/mmc.h index 228d77139..214b9edc8 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -335,7 +335,11 @@ int mmc_start_init(struct mmc *mmc);  void mmc_set_preinit(struct mmc *mmc, int preinit);  #ifdef CONFIG_GENERIC_MMC +#ifdef CONFIG_MMC_SPI  #define mmc_host_is_spi(mmc)	((mmc)->host_caps & MMC_MODE_SPI) +#else +#define mmc_host_is_spi(mmc)	0 +#endif  struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);  #else  int mmc_legacy_init(int verbose); diff --git a/include/sdhci.h b/include/sdhci.h index b18b87312..74d06ae18 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -192,6 +192,8 @@  #define   SDHCI_SPEC_200	1  #define   SDHCI_SPEC_300	2 +#define SDHCI_GET_VERSION(x) (x->version & SDHCI_SPEC_VER_MASK) +  /*   * End of controller registers.   */ @@ -210,6 +212,7 @@  #define SDHCI_QUIRK_NO_CD		(1 << 5)  #define SDHCI_QUIRK_WAIT_SEND_CMD	(1 << 6)  #define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 7) +#define SDHCI_QUIRK_USE_WIDE8		(1 << 8)  /* to make gcc happy */  struct sdhci_host; |