diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/mmc/dw_mmc.c | 385 | ||||
| -rw-r--r-- | drivers/mmc/fsl_esdhc.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/gen_atmel_mci.c | 15 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 129 | ||||
| -rw-r--r-- | drivers/mmc/mmc_spi.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/mxsmmc.c | 36 | ||||
| -rw-r--r-- | drivers/mmc/pxa_mmc.c | 643 | ||||
| -rw-r--r-- | drivers/mmc/s5p_sdhci.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/sdhci.c | 12 | 
10 files changed, 457 insertions, 774 deletions
| diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 565ba6a38..a1dd7302b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -41,12 +41,12 @@ COBJS-$(CONFIG_MV_SDHCI) += mv_sdhci.o  COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o  COBJS-$(CONFIG_MXS_MMC) += mxsmmc.o  COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o -COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o  COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o  COBJS-$(CONFIG_SDHCI) += sdhci.o  COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o  COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o  COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o +COBJS-$(CONFIG_DWMMC) += dw_mmc.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c new file mode 100644 index 000000000..4070d4ea5 --- /dev/null +++ b/drivers/mmc/dw_mmc.c @@ -0,0 +1,385 @@ +/* + * (C) Copyright 2012 SAMSUNG Electronics + * Jaehoon Chung <jh80.chung@samsung.com> + * Rajeshawari Shinde <rajeshwari.s@samsung.com> + * + * 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 <common.h> +#include <malloc.h> +#include <mmc.h> +#include <dwmmc.h> +#include <asm/arch/clk.h> +#include <asm-generic/errno.h> + +#define PAGE_SIZE 4096 + +static int dwmci_wait_reset(struct dwmci_host *host, u32 value) +{ +	unsigned long timeout = 1000; +	u32 ctrl; + +	dwmci_writel(host, DWMCI_CTRL, value); + +	while (timeout--) { +		ctrl = dwmci_readl(host, DWMCI_CTRL); +		if (!(ctrl & DWMCI_RESET_ALL)) +			return 1; +	} +	return 0; +} + +static void dwmci_set_idma_desc(struct dwmci_idmac *idmac, +		u32 desc0, u32 desc1, u32 desc2) +{ +	struct dwmci_idmac *desc = idmac; + +	desc->flags = desc0; +	desc->cnt = desc1; +	desc->addr = desc2; +	desc->next_addr = (unsigned int)desc + sizeof(struct dwmci_idmac); +} + +static void dwmci_prepare_data(struct dwmci_host *host, +		struct mmc_data *data) +{ +	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; + +	dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET); + +	data_start = (ulong)cur_idmac; +	dwmci_writel(host, DWMCI_DBADDR, (unsigned int)cur_idmac); + +	if (data->flags == MMC_DATA_READ) +		start_addr = (unsigned int)data->dest; +	else +		start_addr = (unsigned int)data->src; + +	do { +		flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH ; +		flags |= (i == 0) ? DWMCI_IDMAC_FS : 0; +		if (blk_cnt <= 8) { +			flags |= DWMCI_IDMAC_LD; +			cnt = data->blocksize * blk_cnt; +		} else +			cnt = data->blocksize * 8; + +		dwmci_set_idma_desc(cur_idmac, flags, cnt, +				start_addr + (i * PAGE_SIZE)); + +		if(blk_cnt < 8) +			break; +		blk_cnt -= 8; +		cur_idmac++; +		i++; +	} while(1); + +	data_end = (ulong)cur_idmac; +	flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN); + +	ctrl = dwmci_readl(host, DWMCI_CTRL); +	ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN; +	dwmci_writel(host, DWMCI_CTRL, ctrl); + +	ctrl = dwmci_readl(host, DWMCI_BMOD); +	ctrl |= DWMCI_BMOD_IDMAC_FB | DWMCI_BMOD_IDMAC_EN; +	dwmci_writel(host, DWMCI_BMOD, ctrl); + +	dwmci_writel(host, DWMCI_BLKSIZ, data->blocksize); +	dwmci_writel(host, DWMCI_BYTCNT, data->blocksize * data->blocks); +} + +static int dwmci_set_transfer_mode(struct dwmci_host *host, +		struct mmc_data *data) +{ +	unsigned long mode; + +	mode = DWMCI_CMD_DATA_EXP; +	if (data->flags & MMC_DATA_WRITE) +		mode |= DWMCI_CMD_RW; + +	return mode; +} + +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; +	int flags = 0, i; +	unsigned int timeout = 100000; +	u32 retry = 10000; +	u32 mask, ctrl; + +	while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) { +		if (timeout == 0) { +			printf("Timeout on data busy\n"); +			return TIMEOUT; +		} +		timeout--; +	} + +	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); + +	if (data) +		dwmci_prepare_data(host, data); + + +	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); + +	if (data) +		flags = dwmci_set_transfer_mode(host, data); + +	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) +		return -1; + +	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) +		flags |= DWMCI_CMD_ABORT_STOP; +	else +		flags |= DWMCI_CMD_PRV_DAT_WAIT; + +	if (cmd->resp_type & MMC_RSP_PRESENT) { +		flags |= DWMCI_CMD_RESP_EXP; +		if (cmd->resp_type & MMC_RSP_136) +			flags |= DWMCI_CMD_RESP_LENGTH; +	} + +	if (cmd->resp_type & MMC_RSP_CRC) +		flags |= DWMCI_CMD_CHECK_CRC; + +	flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); + +	debug("Sending CMD%d\n",cmd->cmdidx); + +	dwmci_writel(host, DWMCI_CMD, flags); + +	for (i = 0; i < retry; i++) { +		mask = dwmci_readl(host, DWMCI_RINTSTS); +		if (mask & DWMCI_INTMSK_CDONE) { +			if (!data) +				dwmci_writel(host, DWMCI_RINTSTS, mask); +			break; +		} +	} + +	if (i == retry) +		return TIMEOUT; + +	if (mask & DWMCI_INTMSK_RTO) { +		debug("Response Timeout..\n"); +		return TIMEOUT; +	} else if (mask & DWMCI_INTMSK_RE) { +		debug("Response Error..\n"); +		return -1; +	} + + +	if (cmd->resp_type & MMC_RSP_PRESENT) { +		if (cmd->resp_type & MMC_RSP_136) { +			cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); +			cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); +			cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); +			cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); +		} else { +			cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); +		} +	} + +	if (data) { +		do { +			mask = dwmci_readl(host, DWMCI_RINTSTS); +			if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) { +				debug("DATA ERROR!\n"); +				return -1; +			} +		} while (!(mask & DWMCI_INTMSK_DTO)); + +		dwmci_writel(host, DWMCI_RINTSTS, mask); + +		ctrl = dwmci_readl(host, DWMCI_CTRL); +		ctrl &= ~(DWMCI_DMA_EN); +		dwmci_writel(host, DWMCI_CTRL, ctrl); +	} + +	udelay(100); + +	return 0; +} + +static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) +{ +	u32 div, status; +	int timeout = 10000; +	unsigned long sclk; + +	if (freq == host->clock) +		return 0; + +	/* +	 * If host->mmc_clk didn't define, +	 * then assume that host->bus_hz is source clock value. +	 * host->bus_hz should be set from user. +	 */ +	if (host->mmc_clk) +		sclk = host->mmc_clk(host->dev_index); +	else if (host->bus_hz) +		sclk = host->bus_hz; +	else { +		printf("Didn't get source clock value..\n"); +		return -EINVAL; +	} + +	div = DIV_ROUND_UP(sclk, 2 * freq); + +	dwmci_writel(host, DWMCI_CLKENA, 0); +	dwmci_writel(host, DWMCI_CLKSRC, 0); + +	dwmci_writel(host, DWMCI_CLKDIV, div); +	dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | +			DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + +	do { +		status = dwmci_readl(host, DWMCI_CMD); +		if (timeout-- < 0) { +			printf("TIMEOUT error!!\n"); +			return -ETIMEDOUT; +		} +	} while (status & DWMCI_CMD_START); + +	dwmci_writel(host, DWMCI_CLKENA, DWMCI_CLKEN_ENABLE | +			DWMCI_CLKEN_LOW_PWR); + +	dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_PRV_DAT_WAIT | +			DWMCI_CMD_UPD_CLK | DWMCI_CMD_START); + +	timeout = 10000; +	do { +		status = dwmci_readl(host, DWMCI_CMD); +		if (timeout-- < 0) { +			printf("TIMEOUT error!!\n"); +			return -ETIMEDOUT; +		} +	} while (status & DWMCI_CMD_START); + +	host->clock = freq; + +	return 0; +} + +static void dwmci_set_ios(struct mmc *mmc) +{ +	struct dwmci_host *host = (struct dwmci_host *)mmc->priv; +	u32 ctype; + +	debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); + +	dwmci_setup_bus(host, mmc->clock); +	switch (mmc->bus_width) { +	case 8: +		ctype = DWMCI_CTYPE_8BIT; +		break; +	case 4: +		ctype = DWMCI_CTYPE_4BIT; +		break; +	default: +		ctype = DWMCI_CTYPE_1BIT; +		break; +	} + +	dwmci_writel(host, DWMCI_CTYPE, ctype); + +	if (host->clksel) +		host->clksel(host); +} + +static int dwmci_init(struct mmc *mmc) +{ +	struct dwmci_host *host = (struct dwmci_host *)mmc->priv; +	u32 fifo_size, fifoth_val; + +	dwmci_writel(host, DWMCI_PWREN, 1); + +	if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) { +		debug("%s[%d] Fail-reset!!\n",__func__,__LINE__); +		return -1; +	} + +	dwmci_writel(host, DWMCI_RINTSTS, 0xFFFFFFFF); +	dwmci_writel(host, DWMCI_INTMASK, 0); + +	dwmci_writel(host, DWMCI_TMOUT, 0xFFFFFFFF); + +	dwmci_writel(host, DWMCI_IDINTEN, 0); +	dwmci_writel(host, DWMCI_BMOD, 1); + +	fifo_size = dwmci_readl(host, DWMCI_FIFOTH); +	if (host->fifoth_val) +		fifoth_val = host->fifoth_val; +	else +		fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_size/2 -1) | +			TX_WMARK(fifo_size/2); +	dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); + +	dwmci_writel(host, DWMCI_CLKENA, 0); +	dwmci_writel(host, DWMCI_CLKSRC, 0); + +	return 0; +} + +int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk) +{ +	struct mmc *mmc; +	int err = 0; + +	mmc = malloc(sizeof(struct mmc)); +	if (!mmc) { +		printf("mmc malloc fail!\n"); +		return -1; +	} + +	mmc->priv = host; +	host->mmc = mmc; + +	sprintf(mmc->name, "%s", host->name); +	mmc->send_cmd = dwmci_send_cmd; +	mmc->set_ios = dwmci_set_ios; +	mmc->init = dwmci_init; +	mmc->f_min = min_clk; +	mmc->f_max = max_clk; + +	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + +	mmc->host_caps = host->caps; + +	if (host->buswidth == 8) { +		mmc->host_caps |= MMC_MODE_8BIT; +		mmc->host_caps &= ~MMC_MODE_4BIT; +	} else { +		mmc->host_caps |= MMC_MODE_4BIT; +		mmc->host_caps &= ~MMC_MODE_8BIT; +	} +	mmc->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_HC; + +	err = mmc_register(mmc); + +	return err; +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index aa6a9f13e..e93e38ac4 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -68,7 +68,7 @@ struct fsl_esdhc {  };  /* Return the XFERTYP flags for a given command and data packet */ -uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data) +static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)  {  	uint xfertyp = 0; diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c index 4968c5e49..67b2dbe8d 100644 --- a/drivers/mmc/gen_atmel_mci.c +++ b/drivers/mmc/gen_atmel_mci.c @@ -87,6 +87,11 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)  		 | MMCI_BF(BLKLEN, blklen)  		 | MMCI_BIT(RDPROOF)  		 | MMCI_BIT(WRPROOF)), &mci->mr); +	/* +	 * On some new platforms BLKLEN in mci->mr is ignored. +	 * Should use the BLKLEN in the block register. +	 */ +	writel(MMCI_BF(BLKLEN, blklen), &mci->blkr);  	initialized = 1;  } @@ -183,6 +188,12 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  	/* Figure out the transfer arguments */  	cmdr = mci_encode_cmd(cmd, data, &error_flags); +	/* For multi blocks read/write, set the block register */ +	if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) +			|| (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) +		writel(data->blocks | MMCI_BF(BLKLEN, mmc->read_bl_len), +			&mci->blkr); +  	/* Send the command */  	writel(cmd->cmdarg, &mci->argr);  	writel(cmdr, &mci->cmdr); @@ -310,8 +321,8 @@ static int mci_init(struct mmc *mmc)  	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */  	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */ -	/* Initial Time-outs */ -	writel(0x5f, &mci->dtor); +	/* This delay can be optimized, but stick with max value */ +	writel(0x7f, &mci->dtor);  	/* Disable Interrupts */  	writel(~0UL, &mci->idr); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index a60cfe1cb..5ffd8c59e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -47,104 +47,14 @@ int __board_mmc_getcd(struct mmc *mmc) {  int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,  	alias("__board_mmc_getcd"))); -#ifdef CONFIG_MMC_BOUNCE_BUFFER -static int mmc_bounce_need_bounce(struct mmc_data *orig) -{ -	ulong addr, len; - -	if (orig->flags & MMC_DATA_READ) -		addr = (ulong)orig->dest; -	else -		addr = (ulong)orig->src; - -	if (addr % ARCH_DMA_MINALIGN) { -		debug("MMC: Unaligned data destination address %08lx!\n", addr); -		return 1; -	} - -	len = (ulong)(orig->blocksize * orig->blocks); -	if (len % ARCH_DMA_MINALIGN) { -		debug("MMC: Unaligned data destination length %08lx!\n", len); -		return 1; -	} - -	return 0; -} - -static int mmc_bounce_buffer_start(struct mmc_data *backup, -					struct mmc_data *orig) -{ -	ulong origlen, len; -	void *buffer; - -	if (!orig) -		return 0; - -	if (!mmc_bounce_need_bounce(orig)) -		return 0; - -	memcpy(backup, orig, sizeof(struct mmc_data)); - -	origlen = orig->blocksize * orig->blocks; -	len = roundup(origlen, ARCH_DMA_MINALIGN); -	buffer = memalign(ARCH_DMA_MINALIGN, len); -	if (!buffer) { -		puts("MMC: Error allocating MMC bounce buffer!\n"); -		return 1; -	} - -	if (orig->flags & MMC_DATA_READ) { -		orig->dest = buffer; -	} else { -		memcpy(buffer, orig->src, origlen); -		orig->src = buffer; -	} - -	return 0; -} - -static void mmc_bounce_buffer_stop(struct mmc_data *backup, -					struct mmc_data *orig) -{ -	ulong len; - -	if (!orig) -		return; - -	if (!mmc_bounce_need_bounce(backup)) -		return; - -	if (backup->flags & MMC_DATA_READ) { -		len = backup->blocksize * backup->blocks; -		memcpy(backup->dest, orig->dest, len); -		free(orig->dest); -		orig->dest = backup->dest; -	} else { -		free((void *)orig->src); -		orig->src = backup->src; -	} - -	return; - -} -#else -static inline int mmc_bounce_buffer_start(struct mmc_data *backup, -					struct mmc_data *orig) { return 0; } -static inline void mmc_bounce_buffer_stop(struct mmc_data *backup, -					struct mmc_data *orig) { } -#endif - -int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +static 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)); -	ret = mmc_bounce_buffer_start(&backup, data); -	if (ret) -		return ret; -  #ifdef CONFIG_MMC_TRACE  	int i;  	u8 *ptr; @@ -196,11 +106,10 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  #else  	ret = mmc->send_cmd(mmc, cmd, data);  #endif -	mmc_bounce_buffer_stop(&backup, data);  	return ret;  } -int mmc_send_status(struct mmc *mmc, int timeout) +static int mmc_send_status(struct mmc *mmc, int timeout)  {  	struct mmc_cmd cmd;  	int err, retries = 5; @@ -244,7 +153,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)  	return 0;  } -int mmc_set_blocklen(struct mmc *mmc, int len) +static int mmc_set_blocklen(struct mmc *mmc, int len)  {  	struct mmc_cmd cmd; @@ -437,7 +346,8 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)  	return blkcnt;  } -int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) +static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, +			   lbaint_t blkcnt)  {  	struct mmc_cmd cmd;  	struct mmc_data data; @@ -507,7 +417,7 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)  	return blkcnt;  } -int mmc_go_idle(struct mmc* mmc) +static int mmc_go_idle(struct mmc *mmc)  {  	struct mmc_cmd cmd;  	int err; @@ -528,8 +438,7 @@ int mmc_go_idle(struct mmc* mmc)  	return 0;  } -int -sd_send_op_cond(struct mmc *mmc) +static int sd_send_op_cond(struct mmc *mmc)  {  	int timeout = 1000;  	int err; @@ -594,7 +503,7 @@ sd_send_op_cond(struct mmc *mmc)  	return 0;  } -int mmc_send_op_cond(struct mmc *mmc) +static int mmc_send_op_cond(struct mmc *mmc)  {  	int timeout = 10000;  	struct mmc_cmd cmd; @@ -658,7 +567,7 @@ int mmc_send_op_cond(struct mmc *mmc)  } -int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) +static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)  {  	struct mmc_cmd cmd;  	struct mmc_data data; @@ -680,7 +589,7 @@ int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)  } -int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) +static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)  {  	struct mmc_cmd cmd;  	int timeout = 1000; @@ -702,7 +611,7 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)  } -int mmc_change_freq(struct mmc *mmc) +static int mmc_change_freq(struct mmc *mmc)  {  	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512);  	char cardtype; @@ -772,7 +681,7 @@ int mmc_getcd(struct mmc *mmc)  	return cd;  } -int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) +static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)  {  	struct mmc_cmd cmd;  	struct mmc_data data; @@ -793,7 +702,7 @@ int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)  } -int sd_change_freq(struct mmc *mmc) +static int sd_change_freq(struct mmc *mmc)  {  	int err;  	struct mmc_cmd cmd; @@ -932,7 +841,7 @@ static const int multipliers[] = {  	80,  }; -void mmc_set_ios(struct mmc *mmc) +static void mmc_set_ios(struct mmc *mmc)  {  	mmc->set_ios(mmc);  } @@ -950,14 +859,14 @@ void mmc_set_clock(struct mmc *mmc, uint clock)  	mmc_set_ios(mmc);  } -void mmc_set_bus_width(struct mmc *mmc, uint width) +static void mmc_set_bus_width(struct mmc *mmc, uint width)  {  	mmc->bus_width = width;  	mmc_set_ios(mmc);  } -int mmc_startup(struct mmc *mmc) +static int mmc_startup(struct mmc *mmc)  {  	int err, width;  	uint mult, freq; @@ -1105,7 +1014,7 @@ int mmc_startup(struct mmc *mmc)  	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {  		/* check  ext_csd version and capacity */  		err = mmc_send_ext_csd(mmc, ext_csd); -		if (!err & (ext_csd[EXT_CSD_REV] >= 2)) { +		if (!err && (ext_csd[EXT_CSD_REV] >= 2)) {  			/*  			 * According to the JEDEC Standard, the value of  			 * ext_csd's capacity is valid if the value is more @@ -1240,7 +1149,7 @@ int mmc_startup(struct mmc *mmc)  	return 0;  } -int mmc_send_if_cond(struct mmc *mmc) +static int mmc_send_if_cond(struct mmc *mmc)  {  	struct mmc_cmd cmd;  	int err; diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index de43a8535..11ba532b0 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -176,8 +176,8 @@ static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,  	u8 r1;  	int i;  	int ret = 0; -	debug("%s:cmd%d %x %x %x\n", __func__, -	      cmd->cmdidx, cmd->resp_type, cmd->cmdarg, cmd->flags); +	debug("%s:cmd%d %x %x\n", __func__, +	      cmd->cmdidx, cmd->resp_type, cmd->cmdarg);  	spi_claim_bus(spi);  	spi_cs_activate(spi);  	r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index c80b41b19..109acbf62 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -42,6 +42,7 @@  #include <asm/arch/imx-regs.h>  #include <asm/arch/sys_proto.h>  #include <asm/arch/dma.h> +#include <bouncebuf.h>  struct mxsmmc_priv {  	int			id; @@ -95,28 +96,33 @@ static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data)  static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)  {  	uint32_t data_count = data->blocksize * data->blocks; -	uint32_t cache_data_count; +	uint32_t cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN);  	int dmach;  	struct mxs_dma_desc *desc = priv->desc; +	void *addr, *backup; +	uint8_t flags;  	memset(desc, 0, sizeof(struct mxs_dma_desc));  	desc->address = (dma_addr_t)desc; -	if (data_count % ARCH_DMA_MINALIGN) -		cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); -	else -		cache_data_count = data_count; -  	if (data->flags & MMC_DATA_READ) {  		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; -		priv->desc->cmd.address = (dma_addr_t)data->dest; +		addr = data->dest; +		flags = GEN_BB_WRITE;  	} else {  		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; -		priv->desc->cmd.address = (dma_addr_t)data->src; +		addr = (void *)data->src; +		flags = GEN_BB_READ; +	} + +	bounce_buffer_start(&addr, data_count, &backup, flags); + +	priv->desc->cmd.address = (dma_addr_t)addr; +	if (data->flags & MMC_DATA_WRITE) {  		/* Flush data to DRAM so DMA can pick them up */ -		flush_dcache_range((uint32_t)priv->desc->cmd.address, -			(uint32_t)(priv->desc->cmd.address + cache_data_count)); +		flush_dcache_range((uint32_t)addr, +			(uint32_t)(addr) + cache_data_count);  	}  	/* Invalidate the area, so no writeback into the RAM races with DMA */ @@ -128,15 +134,19 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)  	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;  	mxs_dma_desc_append(dmach, priv->desc); -	if (mxs_dma_go(dmach)) +	if (mxs_dma_go(dmach)) { +		bounce_buffer_stop(&addr, data_count, &backup, flags);  		return COMM_ERR; +	}  	/* The data arrived into DRAM, invalidate cache over them */  	if (data->flags & MMC_DATA_READ) { -		invalidate_dcache_range((uint32_t)priv->desc->cmd.address, -			(uint32_t)(priv->desc->cmd.address + cache_data_count)); +		invalidate_dcache_range((uint32_t)addr, +			(uint32_t)(addr) + cache_data_count);  	} +	bounce_buffer_stop(&addr, data_count, &backup, flags); +  	return 0;  } diff --git a/drivers/mmc/pxa_mmc.c b/drivers/mmc/pxa_mmc.c deleted file mode 100644 index 80c444503..000000000 --- a/drivers/mmc/pxa_mmc.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * (C) Copyright 2003 - * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net - * - * 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 <mmc.h> -#include <asm/errno.h> -#include <asm/arch/hardware.h> -#include <part.h> -#include <asm/io.h> - -#include "pxa_mmc.h" - -extern int fat_register_device(block_dev_desc_t * dev_desc, int part_no); - -static block_dev_desc_t mmc_dev; - -block_dev_desc_t *mmc_get_dev(int dev) -{ -	return ((block_dev_desc_t *) & mmc_dev); -} - -/* - * FIXME needs to read cid and csd info to determine block size - * and other parameters - */ -static uchar mmc_buf[MMC_BLOCK_SIZE]; -static uchar spec_ver; -static int mmc_ready = 0; -static int wide = 0; - -static uint32_t * -/****************************************************/ -mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat) -/****************************************************/ -{ -	static uint32_t resp[4], a, b, c; -	uint32_t status; -	int i; - -	debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl, -	      cmdat | wide); -	writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); -	writel(~MMC_I_MASK_CLK_IS_OFF, MMC_I_MASK); -	while (!(readl(MMC_I_REG) & MMC_I_REG_CLK_IS_OFF)) -		; -	writel(cmd, MMC_CMD); -	writel(argh, MMC_ARGH); -	writel(argl, MMC_ARGL); -	writel(cmdat | wide, MMC_CMDAT); -	writel(~MMC_I_MASK_END_CMD_RES, MMC_I_MASK); -	writel(MMC_STRPCL_START_CLK, MMC_STRPCL); -	while (!(readl(MMC_I_REG) & MMC_I_REG_END_CMD_RES)) -		; - -	status = readl(MMC_STAT); -	debug("MMC status 0x%08x\n", status); -	if (status & MMC_STAT_TIME_OUT_RESPONSE) { -		return 0; -	} - -	/* Linux says: -	 * Did I mention this is Sick.  We always need to -	 * discard the upper 8 bits of the first 16-bit word. -	 */ -	a = (readl(MMC_RES) & 0xffff); -	for (i = 0; i < 4; i++) { -		b = (readl(MMC_RES) & 0xffff); -		c = (readl(MMC_RES) & 0xffff); -		resp[i] = (a << 24) | (b << 8) | (c >> 8); -		a = c; -		debug("MMC resp[%d] = %#08x\n", i, resp[i]); -	} - -	return resp; -} - -int -/****************************************************/ -mmc_block_read(uchar * dst, uint32_t src, int len) -/****************************************************/ -{ -	ushort argh, argl; -	ulong status; - -	if (len == 0) { -		return 0; -	} - -	debug("mmc_block_rd dst %p src %08x len %d\n", dst, src, len); - -	argh = len >> 16; -	argl = len & 0xffff; - -	/* set block len */ -	mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); - -	/* send read command */ -	argh = src >> 16; -	argl = src & 0xffff; -	writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); -	writel(0xffff, MMC_RDTO); -	writel(1, MMC_NOB); -	writel(len, MMC_BLKLEN); -	mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl, -		MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK | -		MMC_CMDAT_DATA_EN); - -	writel(~MMC_I_MASK_RXFIFO_RD_REQ, MMC_I_MASK); -	while (len) { -		if (readl(MMC_I_REG) & MMC_I_REG_RXFIFO_RD_REQ) { -#if defined(CONFIG_CPU_PXA27X) || defined(CONFIG_CPU_MONAHANS) -			int i; -			for (i = min(len, 32); i; i--) { -				*dst++ = readb(MMC_RXFIFO); -				len--; -			} -#else -			*dst++ = readb(MMC_RXFIFO); -			len--; -#endif -		} -		status = readl(MMC_STAT); -		if (status & MMC_STAT_ERRORS) { -			printf("MMC_STAT error %lx\n", status); -			return -1; -		} -	} -	writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK); -	while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE)) -		; -	status = readl(MMC_STAT); -	if (status & MMC_STAT_ERRORS) { -		printf("MMC_STAT error %lx\n", status); -		return -1; -	} -	return 0; -} - -int -/****************************************************/ -mmc_block_write(ulong dst, uchar * src, int len) -/****************************************************/ -{ -	ushort argh, argl; -	ulong status; - -	if (len == 0) { -		return 0; -	} - -	debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len); - -	argh = len >> 16; -	argl = len & 0xffff; - -	/* set block len */ -	mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1); - -	/* send write command */ -	argh = dst >> 16; -	argl = dst & 0xffff; -	writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL); -	writel(1, MMC_NOB); -	writel(len, MMC_BLKLEN); -	mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, argh, argl, -		MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK | -		MMC_CMDAT_DATA_EN); - -	writel(~MMC_I_MASK_TXFIFO_WR_REQ, MMC_I_MASK); -	while (len) { -		if (readl(MMC_I_REG) & MMC_I_REG_TXFIFO_WR_REQ) { -			int i, bytes = min(32, len); - -			for (i = 0; i < bytes; i++) { -				writel(*src++, MMC_TXFIFO); -			} -			if (bytes < 32) { -				writel(MMC_PRTBUF_BUF_PART_FULL, MMC_PRTBUF); -			} -			len -= bytes; -		} -		status = readl(MMC_STAT); -		if (status & MMC_STAT_ERRORS) { -			printf("MMC_STAT error %lx\n", status); -			return -1; -		} -	} -	writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK); -	while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE)) -		; -	writel(~MMC_I_MASK_PRG_DONE, MMC_I_MASK); -	while (!(readl(MMC_I_REG) & MMC_I_REG_PRG_DONE)) -		; -	status = readl(MMC_STAT); -	if (status & MMC_STAT_ERRORS) { -		printf("MMC_STAT error %lx\n", status); -		return -1; -	} -	return 0; -} - -int -/****************************************************/ -pxa_mmc_read(long src, uchar * dst, int size) -/****************************************************/ -{ -	ulong end, part_start, part_end, part_len, aligned_start, aligned_end; -	ulong mmc_block_size, mmc_block_address; - -	if (size == 0) { -		return 0; -	} - -	if (!mmc_ready) { -		printf("Please initial the MMC first\n"); -		return -1; -	} - -	mmc_block_size = MMC_BLOCK_SIZE; -	mmc_block_address = ~(mmc_block_size - 1); - -	src -= CONFIG_SYS_MMC_BASE; -	end = src + size; -	part_start = ~mmc_block_address & src; -	part_end = ~mmc_block_address & end; -	aligned_start = mmc_block_address & src; -	aligned_end = mmc_block_address & end; - -	/* all block aligned accesses */ -	debug -	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, (ulong) dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	if (part_start) { -		part_len = mmc_block_size - part_start; -		debug -		    ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, (ulong) dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < -		    0) { -			return -1; -		} -		memcpy(dst, mmc_buf + part_start, part_len); -		dst += part_len; -		src += part_len; -	} -	debug -	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, (ulong) dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) { -		debug -		    ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, (ulong) dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_read((uchar *) (dst), src, mmc_block_size)) < 0) { -			return -1; -		} -	} -	debug -	    ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, (ulong) dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	if (part_end && src < end) { -		debug -		    ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, (ulong) dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) { -			return -1; -		} -		memcpy(dst, mmc_buf, part_end); -	} -	return 0; -} - -int -/****************************************************/ -pxa_mmc_write(uchar * src, uint32_t dst, int size) -/****************************************************/ -{ -	ulong end, part_start, part_end, part_len, aligned_start, aligned_end; -	ulong mmc_block_size, mmc_block_address; - -	if (size == 0) { -		return 0; -	} - -	if (!mmc_ready) { -		printf("Please initial the MMC first\n"); -		return -1; -	} - -	mmc_block_size = MMC_BLOCK_SIZE; -	mmc_block_address = ~(mmc_block_size - 1); - -	dst -= CONFIG_SYS_MMC_BASE; -	end = dst + size; -	part_start = ~mmc_block_address & dst; -	part_end = ~mmc_block_address & end; -	aligned_start = mmc_block_address & dst; -	aligned_end = mmc_block_address & end; - -	/* all block aligned accesses */ -	debug -	    ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	if (part_start) { -		part_len = mmc_block_size - part_start; -		debug -		    ("ps src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) < -		    0) { -			return -1; -		} -		memcpy(mmc_buf + part_start, src, part_len); -		if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) < -		    0) { -			return -1; -		} -		dst += part_len; -		src += part_len; -	} -	debug -	    ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) { -		debug -		    ("al src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_write(dst, (uchar *) src, mmc_block_size)) < 0) { -			return -1; -		} -	} -	debug -	    ("src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -	     src, dst, end, part_start, part_end, aligned_start, -	     aligned_end); -	if (part_end && dst < end) { -		debug -		    ("pe src %p dst %08x end %lx pstart %lx pend %lx astart %lx aend %lx\n", -		     src, dst, end, part_start, part_end, aligned_start, -		     aligned_end); -		if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) { -			return -1; -		} -		memcpy(mmc_buf, src, part_end); -		if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) { -			return -1; -		} -	} -	return 0; -} - -static ulong -/****************************************************/ -mmc_bread(int dev_num, ulong blknr, lbaint_t blkcnt, void *dst) -/****************************************************/ -{ -	int mmc_block_size = MMC_BLOCK_SIZE; -	ulong src = blknr * mmc_block_size + CONFIG_SYS_MMC_BASE; - -	pxa_mmc_read(src, (uchar *) dst, blkcnt * mmc_block_size); -	return blkcnt; -} - -#ifdef __GNUC__ -#define likely(x)       __builtin_expect(!!(x), 1) -#define unlikely(x)     __builtin_expect(!!(x), 0) -#else -#define likely(x)	(x) -#define unlikely(x)	(x) -#endif - -#define UNSTUFF_BITS(resp,start,size)					\ -	({								\ -		const int __size = size;				\ -		const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1;	\ -		const int32_t __off = 3 - ((start) / 32);			\ -		const int32_t __shft = (start) & 31;			\ -		uint32_t __res;						\ -									\ -		__res = resp[__off] >> __shft;				\ -		if (__size + __shft > 32)				\ -			__res |= resp[__off-1] << ((32 - __shft) % 32);	\ -		__res & __mask;						\ -	}) - -/* - * Given the decoded CSD structure, decode the raw CID to our CID structure. - */ -static void mmc_decode_cid(uint32_t * resp) -{ -	if (IF_TYPE_SD == mmc_dev.if_type) { -		/* -		 * SD doesn't currently have a version field so we will -		 * have to assume we can parse this. -		 */ -		sprintf((char *)mmc_dev.vendor, -			"Man %02x OEM %c%c \"%c%c%c%c%c\" Date %02u/%04u", -			UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, 112, 8), -			UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, 96, 8), -			UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, 80, 8), -			UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, 64, 8), -			UNSTUFF_BITS(resp, 8, 4), UNSTUFF_BITS(resp, 12, -							       8) + 2000); -		sprintf((char *)mmc_dev.revision, "%d.%d", -			UNSTUFF_BITS(resp, 60, 4), UNSTUFF_BITS(resp, 56, 4)); -		sprintf((char *)mmc_dev.product, "%u", -			UNSTUFF_BITS(resp, 24, 32)); -	} else { -		/* -		 * The selection of the format here is based upon published -		 * specs from sandisk and from what people have reported. -		 */ -		switch (spec_ver) { -		case 0:	/* MMC v1.0 - v1.2 */ -		case 1:	/* MMC v1.4 */ -			sprintf((char *)mmc_dev.vendor, -				"Man %02x%02x%02x \"%c%c%c%c%c%c%c\" Date %02u/%04u", -				UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, -									 112, -									 8), -				UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, -									 96, 8), -				UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, -									80, 8), -				UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, -									64, 8), -				UNSTUFF_BITS(resp, 56, 8), UNSTUFF_BITS(resp, -									48, 8), -				UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, -									4) + -				1997); -			sprintf((char *)mmc_dev.revision, "%d.%d", -				UNSTUFF_BITS(resp, 44, 4), UNSTUFF_BITS(resp, -									40, 4)); -			sprintf((char *)mmc_dev.product, "%u", -				UNSTUFF_BITS(resp, 16, 24)); -			break; - -		case 2:	/* MMC v2.0 - v2.2 */ -		case 3:	/* MMC v3.1 - v3.3 */ -		case 4:	/* MMC v4 */ -			sprintf((char *)mmc_dev.vendor, -				"Man %02x OEM %04x \"%c%c%c%c%c%c\" Date %02u/%04u", -				UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, -									 104, -									 16), -				UNSTUFF_BITS(resp, 96, 8), UNSTUFF_BITS(resp, -									88, 8), -				UNSTUFF_BITS(resp, 80, 8), UNSTUFF_BITS(resp, -									72, 8), -				UNSTUFF_BITS(resp, 64, 8), UNSTUFF_BITS(resp, -									56, 8), -				UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8, -									4) + -				1997); -			sprintf((char *)mmc_dev.product, "%u", -				UNSTUFF_BITS(resp, 16, 32)); -			sprintf((char *)mmc_dev.revision, "N/A"); -			break; - -		default: -			printf("MMC card has unknown MMCA version %d\n", -			       spec_ver); -			break; -		} -	} -	printf("%s card.\nVendor: %s\nProduct: %s\nRevision: %s\n", -	       (IF_TYPE_SD == mmc_dev.if_type) ? "SD" : "MMC", mmc_dev.vendor, -	       mmc_dev.product, mmc_dev.revision); -} - -/* - * Given a 128-bit response, decode to our card CSD structure. - */ -static void mmc_decode_csd(uint32_t * resp) -{ -	unsigned int mult, csd_struct; - -	if (IF_TYPE_SD == mmc_dev.if_type) { -		csd_struct = UNSTUFF_BITS(resp, 126, 2); -		if (csd_struct != 0) { -			printf("SD: unrecognised CSD structure version %d\n", -			       csd_struct); -			return; -		} -	} else { -		/* -		 * We only understand CSD structure v1.1 and v1.2. -		 * v1.2 has extra information in bits 15, 11 and 10. -		 */ -		csd_struct = UNSTUFF_BITS(resp, 126, 2); -		if (csd_struct != 1 && csd_struct != 2) { -			printf("MMC: unrecognised CSD structure version %d\n", -			       csd_struct); -			return; -		} - -		spec_ver = UNSTUFF_BITS(resp, 122, 4); -		mmc_dev.if_type = IF_TYPE_MMC; -	} - -	mult = 1 << (UNSTUFF_BITS(resp, 47, 3) + 2); -	mmc_dev.lba = (1 + UNSTUFF_BITS(resp, 62, 12)) * mult; -	mmc_dev.blksz = 1 << UNSTUFF_BITS(resp, 80, 4); - -	/* FIXME: The following just makes assumes that's the partition type -- should really read it */ -	mmc_dev.part_type = PART_TYPE_DOS; -	mmc_dev.dev = 0; -	mmc_dev.lun = 0; -	mmc_dev.type = DEV_TYPE_HARDDISK; -	mmc_dev.removable = 0; -	mmc_dev.block_read = mmc_bread; - -	printf("Detected: %lu blocks of %lu bytes (%luMB) ", -		mmc_dev.lba, -		mmc_dev.blksz, -		mmc_dev.lba * mmc_dev.blksz / (1024 * 1024)); -} - -int -/****************************************************/ -mmc_legacy_init(int verbose) -/****************************************************/ -{ -	int retries, rc = -ENODEV; -	uint32_t cid_resp[4]; -	uint32_t *resp; -	uint16_t rca = 0; - -	/* Reset device interface type */ -	mmc_dev.if_type = IF_TYPE_UNKNOWN; - -#ifdef CONFIG_CPU_MONAHANS	/* pxa3xx */ -	writel(readl(CKENA) | CKENA_12_MMC0 | CKENA_13_MMC1, CKENA); -#else	/* pxa2xx */ -	writel(readl(CKEN) | CKEN12_MMC, CKEN);	/* enable MMC unit clock */ -#endif -	writel(MMC_CLKRT_0_3125MHZ, MMC_CLKRT); -	writel(MMC_RES_TO_MAX, MMC_RESTO); -	writel(MMC_SPI_DISABLE, MMC_SPI); - -	/* reset */ -	mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, 0, MMC_CMDAT_INIT | MMC_CMDAT_R0); -	udelay(200000); -	retries = 3; -	while (retries--) { -		resp = mmc_cmd(MMC_CMD_APP_CMD, 0, 0, MMC_CMDAT_R1); -		if (!(resp[0] & 0x00000020)) {	/* Card does not support APP_CMD */ -			debug("Card does not support APP_CMD\n"); -			break; -		} - -		/* Select 3.2-3.3V and 3.3-3.4V */ -		resp = mmc_cmd(SD_CMD_APP_SEND_OP_COND, 0x0030, 0x0000, -				MMC_CMDAT_R3 | (retries < 2 ? 0 -					: MMC_CMDAT_INIT)); -		if (resp[0] & 0x80000000) { -			mmc_dev.if_type = IF_TYPE_SD; -			debug("Detected SD card\n"); -			break; -		} -		udelay(200000); -	} - -	if (retries <= 0 || !(IF_TYPE_SD == mmc_dev.if_type)) { -		debug("Failed to detect SD Card, trying MMC\n"); -		resp = -		    mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, MMC_CMDAT_R3); - -		retries = 10; -		while (retries-- && resp && !(resp[0] & 0x80000000)) { -			udelay(200000); -			resp = -			    mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, -				    MMC_CMDAT_R3); -		} -	} - -	/* try to get card id */ -	resp = -	    mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, 0, MMC_CMDAT_R2 | MMC_CMDAT_BUSY); -	if (resp) { -		memcpy(cid_resp, resp, sizeof(cid_resp)); - -		/* MMC exists, get CSD too */ -		resp = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, 0, 0, MMC_CMDAT_R1); -		if (IF_TYPE_SD == mmc_dev.if_type) -			rca = ((resp[0] & 0xffff0000) >> 16); -		resp = mmc_cmd(MMC_CMD_SEND_CSD, rca, 0, MMC_CMDAT_R2); -		if (resp) { -			mmc_decode_csd(resp); -			rc = 0; -			mmc_ready = 1; -		} - -		mmc_decode_cid(cid_resp); -	} - -	writel(0, MMC_CLKRT);		/* 20 MHz */ -	resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1); - -#if defined(CONFIG_CPU_PXA27X) || defined(CONFIG_CPU_MONAHANS) -	if (IF_TYPE_SD == mmc_dev.if_type) { -		resp = mmc_cmd(MMC_CMD_APP_CMD, rca, 0, MMC_CMDAT_R1); -		resp = mmc_cmd(SD_CMD_APP_SET_BUS_WIDTH, 0, 2, MMC_CMDAT_R1); -		wide = MMC_CMDAT_SD_4DAT; -	} -#endif - -	fat_register_device(&mmc_dev, 1);	/* partitions start counting with 1 */ - -	return rc; -} diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index b9782367e..dc49d37f5 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -83,7 +83,8 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)  	host->ioaddr = (void *)regbase;  	host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | -		SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR; +		SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | +		SDHCI_QUIRK_WAIT_SEND_CMD;  	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;  	host->version = sdhci_readw(host, SDHCI_HOST_VERSION); diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 2e3c408bc..7845f873a 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -82,8 +82,15 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,  				unsigned int start_addr)  {  	unsigned int stat, rdy, mask, timeout, block = 0; +#ifdef CONFIG_MMC_SDMA +	unsigned char ctrl; +	ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL); +	ctrl &= ~SDHCI_CTRL_DMA_MASK; +	ctrl |= SDHCI_CTRL_SDMA; +	sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL); +#endif -	timeout = 10000; +	timeout = 1000000;  	rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;  	mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;  	do { @@ -233,6 +240,9 @@ int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,  	if (!ret && data)  		ret = sdhci_transfer_data(host, data, start_addr); +	if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD) +		udelay(1000); +  	stat = sdhci_readl(host, SDHCI_INT_STATUS);  	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);  	if (!ret) { |