Эх сурвалжийг харах

Merge branch 'master' of git://www.denx.de/git/u-boot-mmc

Tom Rini 12 жил өмнө
parent
commit
bdc3ff6e4f

+ 9 - 0
board/lubbock/lubbock.c

@@ -29,6 +29,7 @@
 #include <netdev.h>
 #include <asm/arch/pxa.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-mmc.h>
 #include <asm/io.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -56,6 +57,14 @@ int board_init (void)
 	return 0;
 }
 
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+	pxa_mmc_register(0);
+	return 0;
+}
+#endif
+
 int board_late_init(void)
 {
 	setenv("stdout", "serial");

+ 9 - 0
board/palmtc/palmtc.c

@@ -24,6 +24,7 @@
 #include <serial.h>
 #include <asm/io.h>
 #include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -51,6 +52,14 @@ int board_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+	pxa_mmc_register(0);
+	return 0;
+}
+#endif
+
 int dram_init(void)
 {
 	pxa2xx_dram_init();

+ 9 - 0
board/pxa255_idp/pxa_idp.c

@@ -35,6 +35,7 @@
 #include <command.h>
 #include <asm/io.h>
 #include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -77,6 +78,14 @@ int board_init (void)
 	return 0;
 }
 
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+	pxa_mmc_register(0);
+	return 0;
+}
+#endif
+
 int board_late_init(void)
 {
 	setenv("stdout", "serial");

+ 9 - 0
board/trizepsiv/conxs.c

@@ -34,6 +34,7 @@
 #include <common.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/pxa.h>
+#include <asm/arch/regs-mmc.h>
 #include <netdev.h>
 #include <asm/io.h>
 
@@ -152,3 +153,11 @@ int board_eth_init(bd_t *bis)
 	return dm9000_initialize(bis);
 }
 #endif
+
+#ifdef CONFIG_CMD_MMC
+int board_mmc_init(bd_t *bis)
+{
+	pxa_mmc_register(0);
+	return 0;
+}
+#endif

+ 1 - 0
common/Makefile

@@ -205,6 +205,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 endif
+COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o
 COBJS-y += console.o
 COBJS-y += dlmalloc.o
 COBJS-y += image.o

+ 92 - 0
common/bouncebuf.c

@@ -0,0 +1,92 @@
+/*
+ * Generic bounce buffer implementation
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * 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 <common.h>
+#include <malloc.h>
+#include <errno.h>
+#include <bouncebuf.h>
+
+static int addr_aligned(void *data, size_t len)
+{
+	const ulong align_mask = ARCH_DMA_MINALIGN - 1;
+
+	/* Check if start is aligned */
+	if ((ulong)data & align_mask) {
+		debug("Unaligned start address %p\n", data);
+		return 0;
+	}
+
+	data += len;
+
+	/* Check if end is aligned */
+	if ((ulong)data & align_mask) {
+		debug("Unaligned end address %p\n", data);
+		return 0;
+	}
+
+	/* Aligned */
+	return 1;
+}
+
+int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags)
+{
+	void *tmp;
+	size_t alen;
+
+	if (addr_aligned(*data, len)) {
+		*backup = NULL;
+		return 0;
+	}
+
+	alen = roundup(len, ARCH_DMA_MINALIGN);
+	tmp = memalign(ARCH_DMA_MINALIGN, alen);
+
+	if (!tmp)
+		return -ENOMEM;
+
+	if (flags & GEN_BB_READ)
+		memcpy(tmp, *data, len);
+
+	*backup = *data;
+	*data = tmp;
+
+	return 0;
+}
+
+int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags)
+{
+	void *tmp = *data;
+
+	/* The buffer was already aligned, since "backup" is NULL. */
+	if (!*backup)
+		return 0;
+
+	if (flags & GEN_BB_WRITE)
+		memcpy(*backup, *data, len);
+
+	*data = *backup;
+	free(tmp);
+
+	return 0;
+}

+ 1 - 1
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)

+ 385 - 0
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;
+}

+ 0 - 92
drivers/mmc/mmc.c

@@ -47,93 +47,6 @@ 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)
 {
 	struct mmc_data backup;
@@ -141,10 +54,6 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 
 	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,7 +105,6 @@ 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;
 }
 

+ 2 - 2
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);

+ 23 - 13
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;
 }
 

+ 0 - 643
drivers/mmc/pxa_mmc.c

@@ -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;
-}

+ 2 - 1
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);
 

+ 11 - 1
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) {

+ 87 - 0
include/bouncebuf.h

@@ -0,0 +1,87 @@
+/*
+ * Generic bounce buffer implementation
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * 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
+ */
+
+#ifndef __INCLUDE_BOUNCEBUF_H__
+#define __INCLUDE_BOUNCEBUF_H__
+
+/*
+ * GEN_BB_READ -- Data are read from the buffer eg. by DMA hardware.
+ * The source buffer is copied into the bounce buffer (if unaligned, otherwise
+ * the source buffer is used directly) upon start() call, then the operation
+ * requiring the aligned transfer happens, then the bounce buffer is lost upon
+ * stop() call.
+ */
+#define GEN_BB_READ	(1 << 0)
+/*
+ * GEN_BB_WRITE -- Data are written into the buffer eg. by DMA hardware.
+ * The source buffer starts in an undefined state upon start() call, then the
+ * operation requiring the aligned transfer happens, then the bounce buffer is
+ * copied into the destination buffer (if unaligned, otherwise destination
+ * buffer is used directly) upon stop() call.
+ */
+#define GEN_BB_WRITE	(1 << 1)
+/*
+ * GEN_BB_RW -- Data are read and written into the buffer eg. by DMA hardware.
+ * The source buffer is copied into the bounce buffer (if unaligned, otherwise
+ * the source buffer is used directly) upon start() call, then the  operation
+ * requiring the aligned transfer happens, then the bounce buffer is  copied
+ * into the destination buffer (if unaligned, otherwise destination buffer is
+ * used directly) upon stop() call.
+ */
+#define GEN_BB_RW	(GEN_BB_READ | GEN_BB_WRITE)
+
+#ifdef CONFIG_BOUNCE_BUFFER
+/**
+ * bounce_buffer_start() -- Start the bounce buffer session
+ * data:	pointer to buffer to be aligned
+ * len:		length of the buffer
+ * backup:	pointer to backup buffer (the original value is stored here if
+ *              needed
+ * flags:	flags describing the transaction, see above.
+ */
+int bounce_buffer_start(void **data, size_t len, void **backup, uint8_t flags);
+/**
+ * bounce_buffer_stop() -- Finish the bounce buffer session
+ * data:	pointer to buffer that was aligned
+ * len:		length of the buffer
+ * backup:	pointer to backup buffer (the original value is stored here if
+ *              needed
+ * flags:	flags describing the transaction, see above.
+ */
+int bounce_buffer_stop(void **data, size_t len, void **backup, uint8_t flags);
+#else
+static inline int bounce_buffer_start(void **data, size_t len, void **backup,
+					uint8_t flags)
+{
+	return 0;
+}
+
+static inline int bounce_buffer_stop(void **data, size_t len, void **backup,
+					uint8_t flags)
+{
+	return 0;
+}
+#endif
+
+#endif

+ 1 - 1
include/configs/apx4devkit.h

@@ -132,7 +132,7 @@
 #ifdef CONFIG_CMD_MMC
 #define CONFIG_MMC
 #define CONFIG_GENERIC_MMC
-#define CONFIG_MMC_BOUNCE_BUFFER
+#define CONFIG_BOUNCE_BUFFER
 #define CONFIG_MXS_MMC
 #endif
 

+ 2 - 1
include/configs/lubbock.h

@@ -130,7 +130,8 @@
 #define CONFIG_SYS_CPUSPEED		0x161		/* set core clock to 400/200/100 MHz */
 
 #ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define	CONFIG_GENERIC_MMC
+#define	CONFIG_PXA_MMC_GENERIC
 #define CONFIG_CMD_MMC
 #define CONFIG_SYS_MMC_BASE		0xF0000000
 #endif

+ 1 - 1
include/configs/m28evk.h

@@ -135,7 +135,7 @@
  */
 #ifdef	CONFIG_CMD_MMC
 #define	CONFIG_MMC
-#define	CONFIG_MMC_BOUNCE_BUFFER
+#define	CONFIG_BOUNCE_BUFFER
 #define	CONFIG_GENERIC_MMC
 #define	CONFIG_MXS_MMC
 #endif

+ 1 - 1
include/configs/mx28evk.h

@@ -142,7 +142,7 @@
 #ifdef	CONFIG_CMD_MMC
 #define CONFIG_MMC
 #define CONFIG_GENERIC_MMC
-#define CONFIG_MMC_BOUNCE_BUFFER
+#define CONFIG_BOUNCE_BUFFER
 #define CONFIG_MXS_MMC
 #endif
 

+ 2 - 1
include/configs/palmtc.h

@@ -77,7 +77,8 @@
  */
 #ifdef	CONFIG_CMD_MMC
 #define	CONFIG_MMC
-#define	CONFIG_PXA_MMC
+#define	CONFIG_GENERIC_MMC
+#define	CONFIG_PXA_MMC_GENERIC
 #define	CONFIG_SYS_MMC_BASE		0xF0000000
 #define	CONFIG_CMD_FAT
 #define	CONFIG_CMD_EXT2

+ 2 - 1
include/configs/pxa255_idp.h

@@ -245,7 +245,8 @@
 #define RTC	1				/* enable 32KHz osc */
 
 #ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define	CONFIG_GENERIC_MMC
+#define	CONFIG_PXA_MMC_GENERIC
 #define CONFIG_CMD_MMC
 #define CONFIG_SYS_MMC_BASE		0xF0000000
 #endif

+ 2 - 1
include/configs/trizepsiv.h

@@ -170,7 +170,8 @@
 #define CONFIG_SYS_CPUSPEED		0x207		/* need to look more closely, I think this is Turbo = 2x, L=91Mhz */
 
 #ifdef CONFIG_MMC
-#define CONFIG_PXA_MMC
+#define	CONFIG_GENERIC_MMC
+#define	CONFIG_PXA_MMC_GENERIC
 #define CONFIG_CMD_MMC
 #define CONFIG_SYS_MMC_BASE		0xF0000000
 #endif

+ 191 - 0
include/dwmmc.h

@@ -0,0 +1,191 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung@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
+ *
+ */
+
+#ifndef __DWMMC_HW_H
+#define __DWMMC_HW_H
+
+#include <asm/io.h>
+#include <mmc.h>
+
+#define DWMCI_CTRL		0x000
+#define	DWMCI_PWREN		0x004
+#define DWMCI_CLKDIV		0x008
+#define DWMCI_CLKSRC		0x00C
+#define DWMCI_CLKENA		0x010
+#define DWMCI_TMOUT		0x014
+#define DWMCI_CTYPE		0x018
+#define DWMCI_BLKSIZ		0x01C
+#define DWMCI_BYTCNT		0x020
+#define DWMCI_INTMASK		0x024
+#define DWMCI_CMDARG		0x028
+#define DWMCI_CMD		0x02C
+#define DWMCI_RESP0		0x030
+#define DWMCI_RESP1		0x034
+#define DWMCI_RESP2		0x038
+#define DWMCI_RESP3		0x03C
+#define DWMCI_MINTSTS		0x040
+#define DWMCI_RINTSTS		0x044
+#define DWMCI_STATUS		0x048
+#define DWMCI_FIFOTH		0x04C
+#define DWMCI_CDETECT		0x050
+#define DWMCI_WRTPRT		0x054
+#define DWMCI_GPIO		0x058
+#define DWMCI_TCMCNT		0x05C
+#define DWMCI_TBBCNT		0x060
+#define DWMCI_DEBNCE		0x064
+#define DWMCI_USRID		0x068
+#define DWMCI_VERID		0x06C
+#define DWMCI_HCON		0x070
+#define DWMCI_UHS_REG		0x074
+#define DWMCI_BMOD		0x080
+#define DWMCI_PLDMND		0x084
+#define DWMCI_DBADDR		0x088
+#define DWMCI_IDSTS		0x08C
+#define DWMCI_IDINTEN		0x090
+#define DWMCI_DSCADDR		0x094
+#define DWMCI_BUFADDR		0x098
+#define DWMCI_DATA		0x200
+
+/* Interrupt Mask register */
+#define DWMCI_INTMSK_ALL	0xffffffff
+#define DWMCI_INTMSK_RE		(1 << 1)
+#define DWMCI_INTMSK_CDONE	(1 << 2)
+#define DWMCI_INTMSK_DTO	(1 << 3)
+#define DWMCI_INTMSK_TXDR	(1 << 4)
+#define DWMCI_INTMSK_RXDR	(1 << 5)
+#define DWMCI_INTMSK_DCRC	(1 << 7)
+#define DWMCI_INTMSK_RTO	(1 << 8)
+#define DWMCI_INTMSK_DRTO	(1 << 9)
+#define DWMCI_INTMSK_HTO	(1 << 10)
+#define DWMCI_INTMSK_FRUN	(1 << 11)
+#define DWMCI_INTMSK_HLE	(1 << 12)
+#define DWMCI_INTMSK_SBE	(1 << 13)
+#define DWMCI_INTMSK_ACD	(1 << 14)
+#define DWMCI_INTMSK_EBE	(1 << 15)
+
+/* Raw interrupt Regsiter */
+#define DWMCI_DATA_ERR	(DWMCI_INTMSK_EBE | DWMCI_INTMSK_SBE | DWMCI_INTMSK_HLE |\
+			DWMCI_INTMSK_FRUN | DWMCI_INTMSK_EBE | DWMCI_INTMSK_DCRC)
+#define DWMCI_DATA_TOUT	(DWMCI_INTMSK_HTO | DWMCI_INTMSK_DRTO)
+/* CTRL register */
+#define DWMCI_CTRL_RESET	(1 << 0)
+#define DWMCI_CTRL_FIFO_RESET	(1 << 1)
+#define DWMCI_CTRL_DMA_RESET	(1 << 2)
+#define DWMCI_DMA_EN		(1 << 5)
+#define DWMCI_CTRL_SEND_AS_CCSD	(1 << 10)
+#define DWMCI_IDMAC_EN		(1 << 25)
+#define DWMCI_RESET_ALL		(DWMCI_CTRL_RESET | DWMCI_CTRL_FIFO_RESET |\
+				DWMCI_CTRL_DMA_RESET)
+
+/* CMD register */
+#define DWMCI_CMD_RESP_EXP	(1 << 6)
+#define DWMCI_CMD_RESP_LENGTH	(1 << 7)
+#define DWMCI_CMD_CHECK_CRC	(1 << 8)
+#define DWMCI_CMD_DATA_EXP	(1 << 9)
+#define DWMCI_CMD_RW		(1 << 10)
+#define DWMCI_CMD_SEND_STOP	(1 << 12)
+#define DWMCI_CMD_ABORT_STOP	(1 << 14)
+#define DWMCI_CMD_PRV_DAT_WAIT	(1 << 13)
+#define DWMCI_CMD_UPD_CLK	(1 << 21)
+#define DWMCI_CMD_USE_HOLD_REG	(1 << 29)
+#define DWMCI_CMD_START		(1 << 31)
+
+/* CLKENA register */
+#define DWMCI_CLKEN_ENABLE	(1 << 0)
+#define DWMCI_CLKEN_LOW_PWR	(1 << 16)
+
+/* Card-type registe */
+#define DWMCI_CTYPE_1BIT	0
+#define DWMCI_CTYPE_4BIT	(1 << 0)
+#define DWMCI_CTYPE_8BIT	(1 << 16)
+
+/* Status Register */
+#define DWMCI_BUSY		(1 << 9)
+
+/* FIFOTH Register */
+#define MSIZE(x)		((x) << 28)
+#define RX_WMARK(x)		((x) << 16)
+#define TX_WMARK(x)		(x)
+
+#define DWMCI_IDMAC_OWN		(1 << 31)
+#define DWMCI_IDMAC_CH		(1 << 4)
+#define DWMCI_IDMAC_FS		(1 << 3)
+#define DWMCI_IDMAC_LD		(1 << 2)
+
+/*  Bus Mode Register */
+#define DWMCI_BMOD_IDMAC_RESET	(1 << 0)
+#define DWMCI_BMOD_IDMAC_FB	(1 << 1)
+#define DWMCI_BMOD_IDMAC_EN	(1 << 7)
+
+struct dwmci_host {
+	char *name;
+	void *ioaddr;
+	unsigned int quirks;
+	unsigned int caps;
+	unsigned int version;
+	unsigned int clock;
+	unsigned int bus_hz;
+	int dev_index;
+	int buswidth;
+	u32 fifoth_val;
+	struct mmc *mmc;
+
+	void (*clksel)(struct dwmci_host *host);
+	unsigned int (*mmc_clk)(int dev_index);
+};
+
+struct dwmci_idmac {
+	u32 flags;
+	u32 cnt;
+	u32 addr;
+	u32 next_addr;
+};
+
+static inline void dwmci_writel(struct dwmci_host *host, int reg, u32 val)
+{
+	writel(val, host->ioaddr + reg);
+}
+
+static inline void dwmci_writew(struct dwmci_host *host, int reg, u16 val)
+{
+	writew(val, host->ioaddr + reg);
+}
+
+static inline void dwmci_writeb(struct dwmci_host *host, int reg, u8 val)
+{
+	writeb(val, host->ioaddr + reg);
+}
+static inline u32 dwmci_readl(struct dwmci_host *host, int reg)
+{
+	return readl(host->ioaddr + reg);
+}
+
+static inline u16 dwmci_readw(struct dwmci_host *host, int reg)
+{
+	return readw(host->ioaddr + reg);
+}
+
+static inline u8 dwmci_readb(struct dwmci_host *host, int reg)
+{
+	return readb(host->ioaddr + reg);
+}
+
+int add_dwmci(struct dwmci_host *host, u32 max_clk, u32 min_clk);
+#endif	/* __DWMMC_HW_H */

+ 1 - 0
include/sdhci.h

@@ -224,6 +224,7 @@
 #define SDHCI_QUIRK_NO_HISPD_BIT	(1 << 3)
 #define SDHCI_QUIRK_BROKEN_VOLTAGE	(1 << 4)
 #define SDHCI_QUIRK_NO_CD		(1 << 5)
+#define SDHCI_QUIRK_WAIT_SEND_CMD	(1 << 6)
 
 /* to make gcc happy */
 struct sdhci_host;