ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/drivers/mmc/Makefile b/marvell/uboot/drivers/mmc/Makefile
new file mode 100644
index 0000000..e793ed9
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/Makefile
@@ -0,0 +1,36 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
+obj-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
+obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
+obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o
+obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o
+obj-$(CONFIG_GENERIC_MMC) += mmc.o
+obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+obj-$(CONFIG_MMC_SPI) += mmc_spi.o
+obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
+obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
+obj-$(CONFIG_MXC_MMC) += mxcmmc.o
+obj-$(CONFIG_MXS_MMC) += mxsmmc.o
+obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
+obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
+obj-$(CONFIG_SDHCI) += sdhci.o
+obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
+obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
+obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
+obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
+obj-$(CONFIG_DWMMC) += dw_mmc.o
+obj-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
+obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o
+obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
+else
+obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
+endif
diff --git a/marvell/uboot/drivers/mmc/arm_pl180_mmci.c b/marvell/uboot/drivers/mmc/arm_pl180_mmci.c
new file mode 100644
index 0000000..5a55fe7
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/arm_pl180_mmci.c
@@ -0,0 +1,377 @@
+/*
+ * ARM PrimeCell MultiMedia Card Interface - PL180
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com>
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* #define DEBUG */
+
+#include <asm/io.h>
+#include "common.h"
+#include <errno.h>
+#include <mmc.h>
+#include "arm_pl180_mmci.h"
+#include <malloc.h>
+
+static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
+{
+	u32 hoststatus, statusmask;
+	struct pl180_mmc_host *host = dev->priv;
+
+	statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
+	if ((cmd->resp_type & MMC_RSP_PRESENT))
+		statusmask |= SDI_STA_CMDREND;
+	else
+		statusmask |= SDI_STA_CMDSENT;
+
+	do
+		hoststatus = readl(&host->base->status) & statusmask;
+	while (!hoststatus);
+
+	writel(statusmask, &host->base->status_clear);
+	if (hoststatus & SDI_STA_CTIMEOUT) {
+		debug("CMD%d time out\n", cmd->cmdidx);
+		return TIMEOUT;
+	} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
+		   (cmd->resp_type & MMC_RSP_CRC)) {
+		printf("CMD%d CRC error\n", cmd->cmdidx);
+		return -EILSEQ;
+	}
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		cmd->response[0] = readl(&host->base->response0);
+		cmd->response[1] = readl(&host->base->response1);
+		cmd->response[2] = readl(&host->base->response2);
+		cmd->response[3] = readl(&host->base->response3);
+		debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, "
+			"response[2]:0x%08X, response[3]:0x%08X\n",
+			cmd->cmdidx, cmd->response[0], cmd->response[1],
+			cmd->response[2], cmd->response[3]);
+	}
+
+	return 0;
+}
+
+/* send command to the mmc card and wait for results */
+static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
+{
+	int result;
+	u32 sdi_cmd = 0;
+	struct pl180_mmc_host *host = dev->priv;
+
+	sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
+
+	if (cmd->resp_type) {
+		sdi_cmd |= SDI_CMD_WAITRESP;
+		if (cmd->resp_type & MMC_RSP_136)
+			sdi_cmd |= SDI_CMD_LONGRESP;
+	}
+
+	writel((u32)cmd->cmdarg, &host->base->argument);
+	udelay(COMMAND_REG_DELAY);
+	writel(sdi_cmd, &host->base->command);
+	result = wait_for_command_end(dev, cmd);
+
+	/* After CMD2 set RCA to a none zero value. */
+	if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID))
+		dev->rca = 10;
+
+	/* After CMD3 open drain is switched off and push pull is used. */
+	if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) {
+		u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD;
+		writel(sdi_pwr, &host->base->power);
+	}
+
+	return result;
+}
+
+static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
+{
+	u32 *tempbuff = dest;
+	u64 xfercount = blkcount * blksize;
+	struct pl180_mmc_host *host = dev->priv;
+	u32 status, status_err;
+
+	debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
+
+	status = readl(&host->base->status);
+	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
+			       SDI_STA_RXOVERR);
+	while ((!status_err) && (xfercount >= sizeof(u32))) {
+		if (status & SDI_STA_RXDAVL) {
+			*(tempbuff) = readl(&host->base->fifo);
+			tempbuff++;
+			xfercount -= sizeof(u32);
+		}
+		status = readl(&host->base->status);
+		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT |
+				       SDI_STA_RXOVERR);
+	}
+
+	status_err = status &
+		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
+		 SDI_STA_RXOVERR);
+	while (!status_err) {
+		status = readl(&host->base->status);
+		status_err = status &
+			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND |
+			 SDI_STA_RXOVERR);
+	}
+
+	if (status & SDI_STA_DTIMEOUT) {
+		printf("Read data timed out, xfercount: %llu, status: 0x%08X\n",
+			xfercount, status);
+		return -ETIMEDOUT;
+	} else if (status & SDI_STA_DCRCFAIL) {
+		printf("Read data bytes CRC error: 0x%x\n", status);
+		return -EILSEQ;
+	} else if (status & SDI_STA_RXOVERR) {
+		printf("Read data RX overflow error\n");
+		return -EIO;
+	}
+
+	writel(SDI_ICR_MASK, &host->base->status_clear);
+
+	if (xfercount) {
+		printf("Read data error, xfercount: %llu\n", xfercount);
+		return -ENOBUFS;
+	}
+
+	return 0;
+}
+
+static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
+{
+	u32 *tempbuff = src;
+	int i;
+	u64 xfercount = blkcount * blksize;
+	struct pl180_mmc_host *host = dev->priv;
+	u32 status, status_err;
+
+	debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
+
+	status = readl(&host->base->status);
+	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
+	while (!status_err && xfercount) {
+		if (status & SDI_STA_TXFIFOBW) {
+			if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) {
+				for (i = 0; i < SDI_FIFO_BURST_SIZE; i++)
+					writel(*(tempbuff + i),
+						&host->base->fifo);
+				tempbuff += SDI_FIFO_BURST_SIZE;
+				xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32);
+			} else {
+				while (xfercount >= sizeof(u32)) {
+					writel(*(tempbuff), &host->base->fifo);
+					tempbuff++;
+					xfercount -= sizeof(u32);
+				}
+			}
+		}
+		status = readl(&host->base->status);
+		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT);
+	}
+
+	status_err = status &
+		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
+	while (!status_err) {
+		status = readl(&host->base->status);
+		status_err = status &
+			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND);
+	}
+
+	if (status & SDI_STA_DTIMEOUT) {
+		printf("Write data timed out, xfercount:%llu,status:0x%08X\n",
+		       xfercount, status);
+		return -ETIMEDOUT;
+	} else if (status & SDI_STA_DCRCFAIL) {
+		printf("Write data CRC error\n");
+		return -EILSEQ;
+	}
+
+	writel(SDI_ICR_MASK, &host->base->status_clear);
+
+	if (xfercount) {
+		printf("Write data error, xfercount:%llu", xfercount);
+		return -ENOBUFS;
+	}
+
+	return 0;
+}
+
+static int do_data_transfer(struct mmc *dev,
+			    struct mmc_cmd *cmd,
+			    struct mmc_data *data)
+{
+	int error = -ETIMEDOUT;
+	struct pl180_mmc_host *host = dev->priv;
+	u32 blksz = 0;
+	u32 data_ctrl = 0;
+	u32 data_len = (u32) (data->blocks * data->blocksize);
+
+	if (!host->version2) {
+		blksz = (ffs(data->blocksize) - 1);
+		data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
+	} else {
+		blksz = data->blocksize;
+		data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
+	}
+	data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
+
+	writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
+	writel(data_len, &host->base->datalength);
+	udelay(DATA_REG_DELAY);
+
+	if (data->flags & MMC_DATA_READ) {
+		data_ctrl |= SDI_DCTRL_DTDIR_IN;
+		writel(data_ctrl, &host->base->datactrl);
+
+		error = do_command(dev, cmd);
+		if (error)
+			return error;
+
+		error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks,
+				   (u32)data->blocksize);
+	} else if (data->flags & MMC_DATA_WRITE) {
+		error = do_command(dev, cmd);
+		if (error)
+			return error;
+
+		writel(data_ctrl, &host->base->datactrl);
+		error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
+							(u32)data->blocksize);
+	}
+
+	return error;
+}
+
+static int host_request(struct mmc *dev,
+			struct mmc_cmd *cmd,
+			struct mmc_data *data)
+{
+	int result;
+
+	if (data)
+		result = do_data_transfer(dev, cmd, data);
+	else
+		result = do_command(dev, cmd);
+
+	return result;
+}
+
+/* MMC uses open drain drivers in the enumeration phase */
+static int mmc_host_reset(struct mmc *dev)
+{
+	struct pl180_mmc_host *host = dev->priv;
+
+	writel(host->pwr_init, &host->base->power);
+
+	return 0;
+}
+
+static void host_set_ios(struct mmc *dev)
+{
+	struct pl180_mmc_host *host = dev->priv;
+	u32 sdi_clkcr;
+
+	sdi_clkcr = readl(&host->base->clock);
+
+	/* Ramp up the clock rate */
+	if (dev->clock) {
+		u32 clkdiv = 0;
+		u32 tmp_clock;
+
+		if (dev->clock >= dev->f_max) {
+			clkdiv = 0;
+			dev->clock = dev->f_max;
+		} else {
+			clkdiv = (host->clock_in / dev->clock) - 2;
+		}
+
+		tmp_clock = host->clock_in / (clkdiv + 2);
+		while (tmp_clock > dev->clock) {
+			clkdiv++;
+			tmp_clock = host->clock_in / (clkdiv + 2);
+		}
+
+		if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
+			clkdiv = SDI_CLKCR_CLKDIV_MASK;
+
+		tmp_clock = host->clock_in / (clkdiv + 2);
+		dev->clock = tmp_clock;
+		sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
+		sdi_clkcr |= clkdiv;
+	}
+
+	/* Set the bus width */
+	if (dev->bus_width) {
+		u32 buswidth = 0;
+
+		switch (dev->bus_width) {
+		case 1:
+			buswidth |= SDI_CLKCR_WIDBUS_1;
+			break;
+		case 4:
+			buswidth |= SDI_CLKCR_WIDBUS_4;
+			break;
+		case 8:
+			buswidth |= SDI_CLKCR_WIDBUS_8;
+			break;
+		default:
+			printf("Invalid bus width: %d\n", dev->bus_width);
+			break;
+		}
+		sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
+		sdi_clkcr |= buswidth;
+	}
+
+	writel(sdi_clkcr, &host->base->clock);
+	udelay(CLK_CHANGE_DELAY);
+}
+
+/*
+ * mmc_host_init - initialize the mmc controller.
+ * Set initial clock and power for mmc slot.
+ * Initialize mmc struct and register with mmc framework.
+ */
+int arm_pl180_mmci_init(struct pl180_mmc_host *host)
+{
+	struct mmc *dev;
+	u32 sdi_u32;
+
+	dev = malloc(sizeof(struct mmc));
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(struct mmc));
+	dev->priv = host;
+
+	writel(host->pwr_init, &host->base->power);
+	writel(host->clkdiv_init, &host->base->clock);
+	udelay(CLK_CHANGE_DELAY);
+
+	/* Disable mmc interrupts */
+	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
+	writel(sdi_u32, &host->base->mask0);
+	strncpy(dev->name, host->name, sizeof(dev->name));
+	dev->send_cmd = host_request;
+	dev->set_ios = host_set_ios;
+	dev->init = mmc_host_reset;
+	dev->getcd = NULL;
+	dev->getwp = NULL;
+	dev->host_caps = host->caps;
+	dev->voltages = host->voltages;
+	dev->f_min = host->clock_min;
+	dev->f_max = host->clock_max;
+	dev->b_max = host->b_max;
+	mmc_register(dev);
+	debug("registered mmc interface number is:%d\n", dev->block_dev.dev);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/arm_pl180_mmci.h b/marvell/uboot/drivers/mmc/arm_pl180_mmci.h
new file mode 100644
index 0000000..7234449
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/arm_pl180_mmci.h
@@ -0,0 +1,191 @@
+/*
+ * ARM PrimeCell MultiMedia Card Interface - PL180
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Ulf Hansson <ulf.hansson@stericsson.com>
+ * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com>
+ * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ARM_PL180_MMCI_H__
+#define __ARM_PL180_MMCI_H__
+
+#define COMMAND_REG_DELAY	300
+#define DATA_REG_DELAY		1000
+#define CLK_CHANGE_DELAY	2000
+
+#define INIT_PWR		0xBF /* Power on, full power, not open drain */
+#define ARM_MCLK		(100*1000*1000)
+
+/* SDI Power Control register bits */
+#define SDI_PWR_PWRCTRL_MASK	0x00000003
+#define SDI_PWR_PWRCTRL_ON	0x00000003
+#define SDI_PWR_PWRCTRL_OFF	0x00000000
+#define SDI_PWR_DAT2DIREN	0x00000004
+#define SDI_PWR_CMDDIREN	0x00000008
+#define SDI_PWR_DAT0DIREN	0x00000010
+#define SDI_PWR_DAT31DIREN	0x00000020
+#define SDI_PWR_OPD		0x00000040
+#define SDI_PWR_FBCLKEN		0x00000080
+#define SDI_PWR_DAT74DIREN	0x00000100
+#define SDI_PWR_RSTEN		0x00000200
+
+#define VOLTAGE_WINDOW_MMC	0x00FF8080
+#define VOLTAGE_WINDOW_SD	0x80010000
+
+/* SDI clock control register bits */
+#define SDI_CLKCR_CLKDIV_MASK	0x000000FF
+#define SDI_CLKCR_CLKEN		0x00000100
+#define SDI_CLKCR_PWRSAV	0x00000200
+#define SDI_CLKCR_BYPASS	0x00000400
+#define SDI_CLKCR_WIDBUS_MASK	0x00001800
+#define SDI_CLKCR_WIDBUS_1	0x00000000
+#define SDI_CLKCR_WIDBUS_4	0x00000800
+/* V2 only */
+#define SDI_CLKCR_WIDBUS_8	0x00001000
+#define SDI_CLKCR_NEDGE		0x00002000
+#define SDI_CLKCR_HWFC_EN	0x00004000
+
+#define SDI_CLKCR_CLKDIV_INIT_V1 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */
+#define SDI_CLKCR_CLKDIV_INIT_V2 0x000000FD
+
+/* SDI command register bits */
+#define SDI_CMD_CMDINDEX_MASK	0x000000FF
+#define SDI_CMD_WAITRESP	0x00000040
+#define SDI_CMD_LONGRESP	0x00000080
+#define SDI_CMD_WAITINT		0x00000100
+#define SDI_CMD_WAITPEND	0x00000200
+#define SDI_CMD_CPSMEN		0x00000400
+#define SDI_CMD_SDIOSUSPEND	0x00000800
+#define SDI_CMD_ENDCMDCOMPL	0x00001000
+#define SDI_CMD_NIEN		0x00002000
+#define SDI_CMD_CE_ATACMD	0x00004000
+#define SDI_CMD_CBOOTMODEEN	0x00008000
+
+#define SDI_DTIMER_DEFAULT	0xFFFF0000
+
+/* SDI Status register bits */
+#define SDI_STA_CCRCFAIL	0x00000001
+#define SDI_STA_DCRCFAIL	0x00000002
+#define SDI_STA_CTIMEOUT	0x00000004
+#define SDI_STA_DTIMEOUT	0x00000008
+#define SDI_STA_TXUNDERR	0x00000010
+#define SDI_STA_RXOVERR		0x00000020
+#define SDI_STA_CMDREND		0x00000040
+#define SDI_STA_CMDSENT		0x00000080
+#define SDI_STA_DATAEND		0x00000100
+#define SDI_STA_STBITERR	0x00000200
+#define SDI_STA_DBCKEND		0x00000400
+#define SDI_STA_CMDACT		0x00000800
+#define SDI_STA_TXACT		0x00001000
+#define SDI_STA_RXACT		0x00002000
+#define SDI_STA_TXFIFOBW	0x00004000
+#define SDI_STA_RXFIFOBR	0x00008000
+#define SDI_STA_TXFIFOF		0x00010000
+#define SDI_STA_RXFIFOF		0x00020000
+#define SDI_STA_TXFIFOE		0x00040000
+#define SDI_STA_RXFIFOE		0x00080000
+#define SDI_STA_TXDAVL		0x00100000
+#define SDI_STA_RXDAVL		0x00200000
+#define SDI_STA_SDIOIT		0x00400000
+#define SDI_STA_CEATAEND	0x00800000
+#define SDI_STA_CARDBUSY	0x01000000
+#define SDI_STA_BOOTMODE	0x02000000
+#define SDI_STA_BOOTACKERR	0x04000000
+#define SDI_STA_BOOTACKTIMEOUT	0x08000000
+#define SDI_STA_RSTNEND		0x10000000
+
+/* SDI Interrupt Clear register bits */
+#define SDI_ICR_MASK		0x1DC007FF
+#define SDI_ICR_CCRCFAILC	0x00000001
+#define SDI_ICR_DCRCFAILC	0x00000002
+#define SDI_ICR_CTIMEOUTC	0x00000004
+#define SDI_ICR_DTIMEOUTC	0x00000008
+#define SDI_ICR_TXUNDERRC	0x00000010
+#define SDI_ICR_RXOVERRC	0x00000020
+#define SDI_ICR_CMDRENDC	0x00000040
+#define SDI_ICR_CMDSENTC	0x00000080
+#define SDI_ICR_DATAENDC	0x00000100
+#define SDI_ICR_STBITERRC	0x00000200
+#define SDI_ICR_DBCKENDC	0x00000400
+#define SDI_ICR_SDIOITC		0x00400000
+#define SDI_ICR_CEATAENDC	0x00800000
+#define SDI_ICR_BUSYENDC	0x01000000
+#define SDI_ICR_BOOTACKERRC	0x04000000
+#define SDI_ICR_BOOTACKTIMEOUTC	0x08000000
+#define SDI_ICR_RSTNENDC	0x10000000
+
+#define SDI_MASK0_MASK		0x1FFFFFFF
+
+/* SDI Data control register bits */
+#define SDI_DCTRL_DTEN		0x00000001
+#define SDI_DCTRL_DTDIR_IN	0x00000002
+#define SDI_DCTRL_DTMODE_STREAM	0x00000004
+#define SDI_DCTRL_DMAEN		0x00000008
+#define SDI_DCTRL_DBLKSIZE_MASK	0x000000F0
+#define SDI_DCTRL_RWSTART	0x00000100
+#define SDI_DCTRL_RWSTOP	0x00000200
+#define SDI_DCTRL_RWMOD		0x00000200
+#define SDI_DCTRL_SDIOEN	0x00000800
+#define SDI_DCTRL_DMAREQCTL	0x00001000
+#define SDI_DCTRL_DBOOTMODEEN	0x00002000
+#define SDI_DCTRL_BUSYMODE	0x00004000
+#define SDI_DCTRL_DDR_MODE	0x00008000
+#define SDI_DCTRL_DBLOCKSIZE_V2_MASK   0x7fff0000
+#define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT  16
+
+#define SDI_FIFO_BURST_SIZE	8
+
+struct sdi_registers {
+	u32 power;		/* 0x00*/
+	u32 clock;		/* 0x04*/
+	u32 argument;		/* 0x08*/
+	u32 command;		/* 0x0c*/
+	u32 respcommand;	/* 0x10*/
+	u32 response0;		/* 0x14*/
+	u32 response1;		/* 0x18*/
+	u32 response2;		/* 0x1c*/
+	u32 response3;		/* 0x20*/
+	u32 datatimer;		/* 0x24*/
+	u32 datalength;		/* 0x28*/
+	u32 datactrl;		/* 0x2c*/
+	u32 datacount;		/* 0x30*/
+	u32 status;		/* 0x34*/
+	u32 status_clear;	/* 0x38*/
+	u32 mask0;		/* 0x3c*/
+	u32 mask1;		/* 0x40*/
+	u32 card_select;	/* 0x44*/
+	u32 fifo_count;		/* 0x48*/
+	u32 padding1[(0x80-0x4C)>>2];
+	u32 fifo;		/* 0x80*/
+	u32 padding2[(0xFE0-0x84)>>2];
+	u32 periph_id0;		/* 0xFE0 mmc Peripheral Identifcation Register*/
+	u32 periph_id1;		/* 0xFE4*/
+	u32 periph_id2;		/* 0xFE8*/
+	u32 periph_id3;		/* 0xFEC*/
+	u32 pcell_id0;		/* 0xFF0*/
+	u32 pcell_id1;		/* 0xFF4*/
+	u32 pcell_id2;		/* 0xFF8*/
+	u32 pcell_id3;		/* 0xFFC*/
+};
+
+struct pl180_mmc_host {
+	struct sdi_registers *base;
+	char name[32];
+	unsigned int b_max;
+	unsigned int voltages;
+	unsigned int caps;
+	unsigned int clock_in;
+	unsigned int clock_min;
+	unsigned int clock_max;
+	unsigned int clkdiv_init;
+	unsigned int pwr_init;
+	int version2;
+};
+
+int arm_pl180_mmci_init(struct pl180_mmc_host *);
+
+#endif
diff --git a/marvell/uboot/drivers/mmc/bcm2835_sdhci.c b/marvell/uboot/drivers/mmc/bcm2835_sdhci.c
new file mode 100644
index 0000000..54cfabf
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/bcm2835_sdhci.c
@@ -0,0 +1,190 @@
+/*
+ * This code was extracted from:
+ * git://github.com/gonzoua/u-boot-pi.git master
+ * and hence presumably (C) 2012 Oleksandr Tymoshenko
+ *
+ * Tweaks for U-Boot upstreaming
+ * (C) 2012 Stephen Warren
+ *
+ * Portions (e.g. read/write macros, concepts for back-to-back register write
+ * timing workarounds) obviously extracted from the Linux kernel at:
+ * https://github.com/raspberrypi/linux.git rpi-3.6.y
+ *
+ * The Linux kernel code has the following (c) and license, which is hence
+ * propagated to Oleksandr's tree and here:
+ *
+ * Support for SDHCI device on 2835
+ * Based on sdhci-bcm2708.c (c) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * SDHCI platform device - Arasan SD controller in BCM2708
+ *
+ * Inspired by sdhci-pci.c, by Pierre Ossman
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/arch/timer.h>
+
+/* 400KHz is max freq for card ID etc. Use that as min */
+#define MIN_FREQ 400000
+
+struct bcm2835_sdhci_host {
+	struct sdhci_host host;
+	uint twoticks_delay;
+	ulong last_write;
+};
+
+static inline struct bcm2835_sdhci_host *to_bcm(struct sdhci_host *host)
+{
+	return (struct bcm2835_sdhci_host *)host;
+}
+
+static inline void bcm2835_sdhci_raw_writel(struct sdhci_host *host, u32 val,
+						int reg)
+{
+	struct bcm2835_sdhci_host *bcm_host = to_bcm(host);
+
+	/*
+	 * The Arasan has a bugette whereby it may lose the content of
+	 * successive writes to registers that are within two SD-card clock
+	 * cycles of each other (a clock domain crossing problem).
+	 * It seems, however, that the data register does not have this problem.
+	 * (Which is just as well - otherwise we'd have to nobble the DMA engine
+	 * too)
+	 */
+	while (get_timer_us(bcm_host->last_write) < bcm_host->twoticks_delay)
+		;
+
+	writel(val, host->ioaddr + reg);
+	bcm_host->last_write = get_timer_us(0);
+}
+
+static inline u32 bcm2835_sdhci_raw_readl(struct sdhci_host *host, int reg)
+{
+	return readl(host->ioaddr + reg);
+}
+
+static void bcm2835_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
+{
+	bcm2835_sdhci_raw_writel(host, val, reg);
+}
+
+static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	static u32 shadow;
+	u32 oldval = (reg == SDHCI_COMMAND) ? shadow :
+		bcm2835_sdhci_raw_readl(host, reg & ~3);
+	u32 word_num = (reg >> 1) & 1;
+	u32 word_shift = word_num * 16;
+	u32 mask = 0xffff << word_shift;
+	u32 newval = (oldval & ~mask) | (val << word_shift);
+
+	if (reg == SDHCI_TRANSFER_MODE)
+		shadow = newval;
+	else
+		bcm2835_sdhci_raw_writel(host, newval, reg & ~3);
+}
+
+static void bcm2835_sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	u32 oldval = bcm2835_sdhci_raw_readl(host, reg & ~3);
+	u32 byte_num = reg & 3;
+	u32 byte_shift = byte_num * 8;
+	u32 mask = 0xff << byte_shift;
+	u32 newval = (oldval & ~mask) | (val << byte_shift);
+
+	bcm2835_sdhci_raw_writel(host, newval, reg & ~3);
+}
+
+static u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg)
+{
+	u32 val = bcm2835_sdhci_raw_readl(host, reg);
+
+	return val;
+}
+
+static u16 bcm2835_sdhci_readw(struct sdhci_host *host, int reg)
+{
+	u32 val = bcm2835_sdhci_raw_readl(host, (reg & ~3));
+	u32 word_num = (reg >> 1) & 1;
+	u32 word_shift = word_num * 16;
+	u32 word = (val >> word_shift) & 0xffff;
+
+	return word;
+}
+
+static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg)
+{
+	u32 val = bcm2835_sdhci_raw_readl(host, (reg & ~3));
+	u32 byte_num = reg & 3;
+	u32 byte_shift = byte_num * 8;
+	u32 byte = (val >> byte_shift) & 0xff;
+
+	return byte;
+}
+
+static const struct sdhci_ops bcm2835_ops = {
+	.write_l = bcm2835_sdhci_writel,
+	.write_w = bcm2835_sdhci_writew,
+	.write_b = bcm2835_sdhci_writeb,
+	.read_l = bcm2835_sdhci_readl,
+	.read_w = bcm2835_sdhci_readw,
+	.read_b = bcm2835_sdhci_readb,
+};
+
+int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq)
+{
+	struct bcm2835_sdhci_host *bcm_host;
+	struct sdhci_host *host;
+
+	bcm_host = malloc(sizeof(*bcm_host));
+	if (!bcm_host) {
+		printf("sdhci_host malloc fail!\n");
+		return 1;
+	}
+
+	/*
+	 * See the comments in bcm2835_sdhci_raw_writel().
+	 *
+	 * This should probably be dynamically calculated based on the actual
+	 * frequency. However, this is the longest we'll have to wait, and
+	 * doesn't seem to slow access down too much, so the added complexity
+	 * doesn't seem worth it for now.
+	 *
+	 * 1/MIN_FREQ is (max) time per tick of eMMC clock.
+	 * 2/MIN_FREQ is time for two ticks.
+	 * Multiply by 1000000 to get uS per two ticks.
+	 * +1 for hack rounding.
+	 */
+	bcm_host->twoticks_delay = ((2 * 1000000) / MIN_FREQ) + 1;
+	bcm_host->last_write = 0;
+
+	host = &bcm_host->host;
+	host->name = "bcm2835_sdhci";
+	host->ioaddr = (void *)regbase;
+	host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B |
+		SDHCI_QUIRK_WAIT_SEND_CMD;
+	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+	host->ops = &bcm2835_ops;
+
+	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+	add_sdhci(host, emmc_freq, MIN_FREQ);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/bfin_sdh.c b/marvell/uboot/drivers/mmc/bfin_sdh.c
new file mode 100644
index 0000000..2631174
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/bfin_sdh.c
@@ -0,0 +1,302 @@
+/*
+ * Driver for Blackfin on-chip SDH controller
+ *
+ * Copyright (c) 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <asm/blackfin.h>
+#include <asm/portmux.h>
+#include <asm/mach-common/bits/sdh.h>
+#include <asm/mach-common/bits/dma.h>
+
+#if defined(__ADSPBF50x__) || defined(__ADSPBF51x__) || defined(__ADSPBF60x__)
+# define bfin_read_SDH_CLK_CTL		bfin_read_RSI_CLK_CONTROL
+# define bfin_write_SDH_CLK_CTL		bfin_write_RSI_CLK_CONTROL
+# define bfin_write_SDH_ARGUMENT	bfin_write_RSI_ARGUMENT
+# define bfin_write_SDH_COMMAND		bfin_write_RSI_COMMAND
+# define bfin_read_SDH_RESPONSE0	bfin_read_RSI_RESPONSE0
+# define bfin_read_SDH_RESPONSE1	bfin_read_RSI_RESPONSE1
+# define bfin_read_SDH_RESPONSE2	bfin_read_RSI_RESPONSE2
+# define bfin_read_SDH_RESPONSE3	bfin_read_RSI_RESPONSE3
+# define bfin_write_SDH_DATA_TIMER	bfin_write_RSI_DATA_TIMER
+# define bfin_write_SDH_DATA_LGTH	bfin_write_RSI_DATA_LGTH
+# define bfin_read_SDH_DATA_CTL		bfin_read_RSI_DATA_CONTROL
+# define bfin_write_SDH_DATA_CTL	bfin_write_RSI_DATA_CONTROL
+# define bfin_read_SDH_STATUS		bfin_read_RSI_STATUS
+# define bfin_write_SDH_STATUS_CLR 	bfin_write_RSI_STATUSCL
+# define bfin_read_SDH_CFG		bfin_read_RSI_CONFIG
+# define bfin_write_SDH_CFG		bfin_write_RSI_CONFIG
+# if defined(__ADSPBF60x__)
+# define bfin_read_SDH_BLK_SIZE		bfin_read_RSI_BLKSZ
+# define bfin_write_SDH_BLK_SIZE	bfin_write_RSI_BLKSZ
+# define bfin_write_DMA_START_ADDR	bfin_write_DMA10_START_ADDR
+# define bfin_write_DMA_X_COUNT		bfin_write_DMA10_X_COUNT
+# define bfin_write_DMA_X_MODIFY	bfin_write_DMA10_X_MODIFY
+# define bfin_write_DMA_CONFIG		bfin_write_DMA10_CONFIG
+# else
+# define bfin_read_SDH_PWR_CTL		bfin_read_RSI_PWR_CONTROL
+# define bfin_write_SDH_PWR_CTL		bfin_write_RSI_PWR_CONTROL
+# define bfin_write_DMA_START_ADDR	bfin_write_DMA4_START_ADDR
+# define bfin_write_DMA_X_COUNT		bfin_write_DMA4_X_COUNT
+# define bfin_write_DMA_X_MODIFY	bfin_write_DMA4_X_MODIFY
+# define bfin_write_DMA_CONFIG		bfin_write_DMA4_CONFIG
+# endif
+# define PORTMUX_PINS \
+	{ P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3, P_RSI_CMD, P_RSI_CLK, 0 }
+#elif defined(__ADSPBF54x__)
+# define bfin_write_DMA_START_ADDR	bfin_write_DMA22_START_ADDR
+# define bfin_write_DMA_X_COUNT		bfin_write_DMA22_X_COUNT
+# define bfin_write_DMA_X_MODIFY	bfin_write_DMA22_X_MODIFY
+# define bfin_write_DMA_CONFIG		bfin_write_DMA22_CONFIG
+# define PORTMUX_PINS \
+	{ P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD, 0 }
+#else
+# error no support for this proc yet
+#endif
+
+static int
+sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	unsigned int status, timeout;
+	int cmd = mmc_cmd->cmdidx;
+	int flags = mmc_cmd->resp_type;
+	int arg = mmc_cmd->cmdarg;
+	int ret;
+	u16 sdh_cmd;
+
+	sdh_cmd = cmd | CMD_E;
+	if (flags & MMC_RSP_PRESENT)
+		sdh_cmd |= CMD_RSP;
+	if (flags & MMC_RSP_136)
+		sdh_cmd |= CMD_L_RSP;
+#ifdef RSI_BLKSZ
+	sdh_cmd |= CMD_DATA0_BUSY;
+#endif
+
+	bfin_write_SDH_ARGUMENT(arg);
+	bfin_write_SDH_COMMAND(sdh_cmd);
+
+	/* wait for a while */
+	timeout = 0;
+	do {
+		if (++timeout > 1000000) {
+			status = CMD_TIME_OUT;
+			break;
+		}
+		udelay(1);
+		status = bfin_read_SDH_STATUS();
+	} while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT |
+		CMD_CRC_FAIL)));
+
+	if (flags & MMC_RSP_PRESENT) {
+		mmc_cmd->response[0] = bfin_read_SDH_RESPONSE0();
+		if (flags & MMC_RSP_136) {
+			mmc_cmd->response[1] = bfin_read_SDH_RESPONSE1();
+			mmc_cmd->response[2] = bfin_read_SDH_RESPONSE2();
+			mmc_cmd->response[3] = bfin_read_SDH_RESPONSE3();
+		}
+	}
+
+	if (status & CMD_TIME_OUT)
+		ret = TIMEOUT;
+	else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC)
+		ret = COMM_ERR;
+	else
+		ret = 0;
+
+	bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT |
+				CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT);
+#ifdef RSI_BLKSZ
+	/* wait till card ready */
+	while (!(bfin_read_RSI_ESTAT() & SD_CARD_READY))
+		continue;
+	bfin_write_RSI_ESTAT(SD_CARD_READY);
+#endif
+
+	return ret;
+}
+
+/* set data for single block transfer */
+static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data)
+{
+	u16 data_ctl = 0;
+	u16 dma_cfg = 0;
+	unsigned long data_size = data->blocksize * data->blocks;
+
+	/* Don't support write yet. */
+	if (data->flags & MMC_DATA_WRITE)
+		return UNUSABLE_ERR;
+#ifndef RSI_BLKSZ
+	data_ctl |= ((ffs(data_size) - 1) << 4);
+#else
+	bfin_write_SDH_BLK_SIZE(data_size);
+#endif
+	data_ctl |= DTX_DIR;
+	bfin_write_SDH_DATA_CTL(data_ctl);
+	dma_cfg = WDSIZE_32 | PSIZE_32 | RESTART | WNR | DMAEN;
+
+	bfin_write_SDH_DATA_TIMER(-1);
+
+	blackfin_dcache_flush_invalidate_range(data->dest,
+			data->dest + data_size);
+	/* configure DMA */
+	bfin_write_DMA_START_ADDR(data->dest);
+	bfin_write_DMA_X_COUNT(data_size / 4);
+	bfin_write_DMA_X_MODIFY(4);
+	bfin_write_DMA_CONFIG(dma_cfg);
+	bfin_write_SDH_DATA_LGTH(data_size);
+	/* kick off transfer */
+	bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
+
+	return 0;
+}
+
+
+static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
+		struct mmc_data *data)
+{
+	u32 status;
+	int ret = 0;
+
+	if (data) {
+		ret = sdh_setup_data(mmc, data);
+		if (ret)
+			return ret;
+	}
+
+	ret = sdh_send_cmd(mmc, cmd);
+	if (ret) {
+		bfin_write_SDH_COMMAND(0);
+		bfin_write_DMA_CONFIG(0);
+		bfin_write_SDH_DATA_CTL(0);
+		SSYNC();
+		printf("sending CMD%d failed\n", cmd->cmdidx);
+		return ret;
+	}
+
+	if (data) {
+		do {
+			udelay(1);
+			status = bfin_read_SDH_STATUS();
+		} while (!(status & (DAT_BLK_END | DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN)));
+
+		if (status & DAT_TIME_OUT) {
+			bfin_write_SDH_STATUS_CLR(DAT_TIMEOUT_STAT);
+			ret |= TIMEOUT;
+		} else if (status & (DAT_CRC_FAIL | RX_OVERRUN)) {
+			bfin_write_SDH_STATUS_CLR(DAT_CRC_FAIL_STAT | RX_OVERRUN_STAT);
+			ret |= COMM_ERR;
+		} else
+			bfin_write_SDH_STATUS_CLR(DAT_BLK_END_STAT | DAT_END_STAT);
+
+		if (ret) {
+			printf("tranfering data failed\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+static void sdh_set_clk(unsigned long clk)
+{
+	unsigned long sys_clk;
+	unsigned long clk_div;
+	u16 clk_ctl = 0;
+
+	clk_ctl = bfin_read_SDH_CLK_CTL();
+	if (clk) {
+		/* setting SD_CLK */
+		sys_clk = get_sclk();
+		bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E);
+		if (sys_clk % (2 * clk) == 0)
+			clk_div = sys_clk / (2 * clk) - 1;
+		else
+			clk_div = sys_clk / (2 * clk);
+
+		if (clk_div > 0xff)
+			clk_div = 0xff;
+		clk_ctl |= (clk_div & 0xff);
+		clk_ctl |= CLK_E;
+		bfin_write_SDH_CLK_CTL(clk_ctl);
+	} else
+		bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E);
+}
+
+static void bfin_sdh_set_ios(struct mmc *mmc)
+{
+	u16 cfg = 0;
+	u16 clk_ctl = 0;
+
+	if (mmc->bus_width == 4) {
+		cfg = bfin_read_SDH_CFG();
+#ifndef RSI_BLKSZ
+		cfg &= ~PD_SDDAT3;
+#endif
+		cfg |= PUP_SDDAT3;
+		bfin_write_SDH_CFG(cfg);
+		clk_ctl |= WIDE_BUS_4;
+	}
+	bfin_write_SDH_CLK_CTL(clk_ctl);
+	sdh_set_clk(mmc->clock);
+}
+
+static int bfin_sdh_init(struct mmc *mmc)
+{
+	const unsigned short pins[] = PORTMUX_PINS;
+	int ret;
+
+	/* Initialize sdh controller */
+	ret = peripheral_request_list(pins, "bfin_sdh");
+	if (ret < 0)
+		return ret;
+#if defined(__ADSPBF54x__)
+	bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
+#endif
+	bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
+	/* Disable card detect pin */
+	bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | 0x60);
+#ifndef RSI_BLKSZ
+	bfin_write_SDH_PWR_CTL(PWR_ON | ROD_CTL);
+#else
+	bfin_write_SDH_CFG(bfin_read_SDH_CFG() | PWR_ON);
+#endif
+	return 0;
+}
+
+
+int bfin_mmc_init(bd_t *bis)
+{
+	struct mmc *mmc = NULL;
+
+	mmc = malloc(sizeof(struct mmc));
+
+	if (!mmc)
+		return -ENOMEM;
+	sprintf(mmc->name, "Blackfin SDH");
+	mmc->send_cmd = bfin_sdh_request;
+	mmc->set_ios = bfin_sdh_set_ios;
+	mmc->init = bfin_sdh_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+	mmc->host_caps = MMC_MODE_4BIT;
+
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max = get_sclk();
+	mmc->f_min = mmc->f_max >> 9;
+
+	mmc->b_max = 0;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/davinci_mmc.c b/marvell/uboot/drivers/mmc/davinci_mmc.c
new file mode 100644
index 0000000..b380961
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/davinci_mmc.c
@@ -0,0 +1,394 @@
+/*
+ * Davinci MMC Controller Driver
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/sdmmc_defs.h>
+
+#define DAVINCI_MAX_BLOCKS	(32)
+#define WATCHDOG_COUNT		(100000)
+
+#define get_val(addr)		REG(addr)
+#define set_val(addr, val)	REG(addr) = (val)
+#define set_bit(addr, val)	set_val((addr), (get_val(addr) | (val)))
+#define clear_bit(addr, val)	set_val((addr), (get_val(addr) & ~(val)))
+
+/* Set davinci clock prescalar value based on the required clock in HZ */
+static void dmmc_set_clock(struct mmc *mmc, uint clock)
+{
+	struct davinci_mmc *host = mmc->priv;
+	struct davinci_mmc_regs *regs = host->reg_base;
+	uint clkrt, sysclk2, act_clock;
+
+	if (clock < mmc->f_min)
+		clock = mmc->f_min;
+	if (clock > mmc->f_max)
+		clock = mmc->f_max;
+
+	set_val(&regs->mmcclk, 0);
+	sysclk2 = host->input_clk;
+	clkrt = (sysclk2 / (2 * clock)) - 1;
+
+	/* Calculate the actual clock for the divider used */
+	act_clock = (sysclk2 / (2 * (clkrt + 1)));
+
+	/* Adjust divider if actual clock exceeds the required clock */
+	if (act_clock > clock)
+		clkrt++;
+
+	/* check clock divider boundary and correct it */
+	if (clkrt > 0xFF)
+		clkrt = 0xFF;
+
+	set_val(&regs->mmcclk, (clkrt | MMCCLK_CLKEN));
+}
+
+/* Status bit wait loop for MMCST1 */
+static int
+dmmc_wait_fifo_status(volatile struct davinci_mmc_regs *regs, uint status)
+{
+	uint wdog = WATCHDOG_COUNT;
+
+	while (--wdog && ((get_val(&regs->mmcst1) & status) != status))
+		udelay(10);
+
+	if (!(get_val(&regs->mmcctl) & MMCCTL_WIDTH_4_BIT))
+		udelay(100);
+
+	if (wdog == 0)
+		return COMM_ERR;
+
+	return 0;
+}
+
+/* Busy bit wait loop for MMCST1 */
+static int dmmc_busy_wait(volatile struct davinci_mmc_regs *regs)
+{
+	uint wdog = WATCHDOG_COUNT;
+
+	while (--wdog && (get_val(&regs->mmcst1) & MMCST1_BUSY))
+		udelay(10);
+
+	if (wdog == 0)
+		return COMM_ERR;
+
+	return 0;
+}
+
+/* Status bit wait loop for MMCST0 - Checks for error bits as well */
+static int dmmc_check_status(volatile struct davinci_mmc_regs *regs,
+		uint *cur_st, uint st_ready, uint st_error)
+{
+	uint wdog = WATCHDOG_COUNT;
+	uint mmcstatus = *cur_st;
+
+	while (wdog--) {
+		if (mmcstatus & st_ready) {
+			*cur_st = mmcstatus;
+			mmcstatus = get_val(&regs->mmcst1);
+			return 0;
+		} else if (mmcstatus & st_error) {
+			if (mmcstatus & MMCST0_TOUTRS)
+				return TIMEOUT;
+			printf("[ ST0 ERROR %x]\n", mmcstatus);
+			/*
+			 * Ignore CRC errors as some MMC cards fail to
+			 * initialize on DM365-EVM on the SD1 slot
+			 */
+			if (mmcstatus & MMCST0_CRCRS)
+				return 0;
+			return COMM_ERR;
+		}
+		udelay(10);
+
+		mmcstatus = get_val(&regs->mmcst0);
+	}
+
+	printf("Status %x Timeout ST0:%x ST1:%x\n", st_ready, mmcstatus,
+			get_val(&regs->mmcst1));
+	return COMM_ERR;
+}
+
+/*
+ * Sends a command out on the bus.  Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	struct davinci_mmc *host = mmc->priv;
+	volatile struct davinci_mmc_regs *regs = host->reg_base;
+	uint mmcstatus, status_rdy, status_err;
+	uint i, cmddata, bytes_left = 0;
+	int fifo_words, fifo_bytes, err;
+	char *data_buf = NULL;
+
+	/* Clear status registers */
+	mmcstatus = get_val(&regs->mmcst0);
+	fifo_words = (host->version == MMC_CTLR_VERSION_2) ? 16 : 8;
+	fifo_bytes = fifo_words << 2;
+
+	/* Wait for any previous busy signal to be cleared */
+	dmmc_busy_wait(regs);
+
+	cmddata = cmd->cmdidx;
+	cmddata |= MMCCMD_PPLEN;
+
+	/* Send init clock for CMD0 */
+	if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE)
+		cmddata |= MMCCMD_INITCK;
+
+	switch (cmd->resp_type) {
+	case MMC_RSP_R1b:
+		cmddata |= MMCCMD_BSYEXP;
+		/* Fall-through */
+	case MMC_RSP_R1:    /* R1, R1b, R5, R6, R7 */
+		cmddata |= MMCCMD_RSPFMT_R1567;
+		break;
+	case MMC_RSP_R2:
+		cmddata |= MMCCMD_RSPFMT_R2;
+		break;
+	case MMC_RSP_R3: /* R3, R4 */
+		cmddata |= MMCCMD_RSPFMT_R3;
+		break;
+	}
+
+	set_val(&regs->mmcim, 0);
+
+	if (data) {
+		/* clear previous data transfer if any and set new one */
+		bytes_left = (data->blocksize * data->blocks);
+
+		/* Reset FIFO - Always use 32 byte fifo threshold */
+		set_val(&regs->mmcfifoctl,
+				(MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST));
+
+		if (host->version == MMC_CTLR_VERSION_2)
+			cmddata |= MMCCMD_DMATRIG;
+
+		cmddata |= MMCCMD_WDATX;
+		if (data->flags == MMC_DATA_READ) {
+			set_val(&regs->mmcfifoctl, MMCFIFOCTL_FIFOLEV);
+		} else if (data->flags == MMC_DATA_WRITE) {
+			set_val(&regs->mmcfifoctl,
+					(MMCFIFOCTL_FIFOLEV |
+					 MMCFIFOCTL_FIFODIR));
+			cmddata |= MMCCMD_DTRW;
+		}
+
+		set_val(&regs->mmctod, 0xFFFF);
+		set_val(&regs->mmcnblk, (data->blocks & MMCNBLK_NBLK_MASK));
+		set_val(&regs->mmcblen, (data->blocksize & MMCBLEN_BLEN_MASK));
+
+		if (data->flags == MMC_DATA_WRITE) {
+			uint val;
+			data_buf = (char *)data->src;
+			/* For write, fill FIFO with data before issue of CMD */
+			for (i = 0; (i < fifo_words) && bytes_left; i++) {
+				memcpy((char *)&val, data_buf, 4);
+				set_val(&regs->mmcdxr, val);
+				data_buf += 4;
+				bytes_left -= 4;
+			}
+		}
+	} else {
+		set_val(&regs->mmcblen, 0);
+		set_val(&regs->mmcnblk, 0);
+	}
+
+	set_val(&regs->mmctor, 0x1FFF);
+
+	/* Send the command */
+	set_val(&regs->mmcarghl, cmd->cmdarg);
+	set_val(&regs->mmccmd, cmddata);
+
+	status_rdy = MMCST0_RSPDNE;
+	status_err = (MMCST0_TOUTRS | MMCST0_TOUTRD |
+			MMCST0_CRCWR | MMCST0_CRCRD);
+	if (cmd->resp_type & MMC_RSP_CRC)
+		status_err |= MMCST0_CRCRS;
+
+	mmcstatus = get_val(&regs->mmcst0);
+	err = dmmc_check_status(regs, &mmcstatus, status_rdy, status_err);
+	if (err)
+		return err;
+
+	/* For R1b wait for busy done */
+	if (cmd->resp_type == MMC_RSP_R1b)
+		dmmc_busy_wait(regs);
+
+	/* Collect response from controller for specific commands */
+	if (mmcstatus & MMCST0_RSPDNE) {
+		/* Copy the response to the response buffer */
+		if (cmd->resp_type & MMC_RSP_136) {
+			cmd->response[0] = get_val(&regs->mmcrsp67);
+			cmd->response[1] = get_val(&regs->mmcrsp45);
+			cmd->response[2] = get_val(&regs->mmcrsp23);
+			cmd->response[3] = get_val(&regs->mmcrsp01);
+		} else if (cmd->resp_type & MMC_RSP_PRESENT) {
+			cmd->response[0] = get_val(&regs->mmcrsp67);
+		}
+	}
+
+	if (data == NULL)
+		return 0;
+
+	if (data->flags == MMC_DATA_READ) {
+		/* check for DATDNE along with DRRDY as the controller might
+		 * set the DATDNE without DRRDY for smaller transfers with
+		 * less than FIFO threshold bytes
+		 */
+		status_rdy = MMCST0_DRRDY | MMCST0_DATDNE;
+		status_err = MMCST0_TOUTRD | MMCST0_CRCRD;
+		data_buf = data->dest;
+	} else {
+		status_rdy = MMCST0_DXRDY | MMCST0_DATDNE;
+		status_err = MMCST0_CRCWR;
+	}
+
+	/* Wait until all of the blocks are transferred */
+	while (bytes_left) {
+		err = dmmc_check_status(regs, &mmcstatus, status_rdy,
+				status_err);
+		if (err)
+			return err;
+
+		if (data->flags == MMC_DATA_READ) {
+			/*
+			 * MMC controller sets the Data receive ready bit
+			 * (DRRDY) in MMCST0 even before the entire FIFO is
+			 * full. This results in erratic behavior if we start
+			 * reading the FIFO soon after DRRDY.  Wait for the
+			 * FIFO full bit in MMCST1 for proper FIFO clearing.
+			 */
+			if (bytes_left > fifo_bytes)
+				dmmc_wait_fifo_status(regs, 0x4a);
+			else if (bytes_left == fifo_bytes) {
+				dmmc_wait_fifo_status(regs, 0x40);
+				if (cmd->cmdidx == MMC_CMD_SEND_EXT_CSD)
+					udelay(600);
+			}
+
+			for (i = 0; bytes_left && (i < fifo_words); i++) {
+				cmddata = get_val(&regs->mmcdrr);
+				memcpy(data_buf, (char *)&cmddata, 4);
+				data_buf += 4;
+				bytes_left -= 4;
+			}
+		} else {
+			/*
+			 * MMC controller sets the Data transmit ready bit
+			 * (DXRDY) in MMCST0 even before the entire FIFO is
+			 * empty. This results in erratic behavior if we start
+			 * writing the FIFO soon after DXRDY.  Wait for the
+			 * FIFO empty bit in MMCST1 for proper FIFO clearing.
+			 */
+			dmmc_wait_fifo_status(regs, MMCST1_FIFOEMP);
+			for (i = 0; bytes_left && (i < fifo_words); i++) {
+				memcpy((char *)&cmddata, data_buf, 4);
+				set_val(&regs->mmcdxr, cmddata);
+				data_buf += 4;
+				bytes_left -= 4;
+			}
+			dmmc_busy_wait(regs);
+		}
+	}
+
+	err = dmmc_check_status(regs, &mmcstatus, MMCST0_DATDNE, status_err);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/* Initialize Davinci MMC controller */
+static int dmmc_init(struct mmc *mmc)
+{
+	struct davinci_mmc *host = mmc->priv;
+	struct davinci_mmc_regs *regs = host->reg_base;
+
+	/* Clear status registers explicitly - soft reset doesn't clear it
+	 * If Uboot is invoked from UBL with SDMMC Support, the status
+	 * registers can have uncleared bits
+	 */
+	get_val(&regs->mmcst0);
+	get_val(&regs->mmcst1);
+
+	/* Hold software reset */
+	set_bit(&regs->mmcctl, MMCCTL_DATRST);
+	set_bit(&regs->mmcctl, MMCCTL_CMDRST);
+	udelay(10);
+
+	set_val(&regs->mmcclk, 0x0);
+	set_val(&regs->mmctor, 0x1FFF);
+	set_val(&regs->mmctod, 0xFFFF);
+
+	/* Clear software reset */
+	clear_bit(&regs->mmcctl, MMCCTL_DATRST);
+	clear_bit(&regs->mmcctl, MMCCTL_CMDRST);
+
+	udelay(10);
+
+	/* Reset FIFO - Always use the maximum fifo threshold */
+	set_val(&regs->mmcfifoctl, (MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST));
+	set_val(&regs->mmcfifoctl, MMCFIFOCTL_FIFOLEV);
+
+	return 0;
+}
+
+/* Set buswidth or clock as indicated by the GENERIC_MMC framework */
+static void dmmc_set_ios(struct mmc *mmc)
+{
+	struct davinci_mmc *host = mmc->priv;
+	struct davinci_mmc_regs *regs = host->reg_base;
+
+	/* Set the bus width */
+	if (mmc->bus_width == 4)
+		set_bit(&regs->mmcctl, MMCCTL_WIDTH_4_BIT);
+	else
+		clear_bit(&regs->mmcctl, MMCCTL_WIDTH_4_BIT);
+
+	/* Set clock speed */
+	if (mmc->clock)
+		dmmc_set_clock(mmc, mmc->clock);
+}
+
+/* Called from board_mmc_init during startup. Can be called multiple times
+ * depending on the number of slots available on board and controller
+ */
+int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)
+{
+	struct mmc *mmc;
+
+	mmc = malloc(sizeof(struct mmc));
+	memset(mmc, 0, sizeof(struct mmc));
+
+	sprintf(mmc->name, "davinci");
+	mmc->priv = host;
+	mmc->send_cmd = dmmc_send_cmd;
+	mmc->set_ios = dmmc_set_ios;
+	mmc->init = dmmc_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+
+	mmc->f_min = 200000;
+	mmc->f_max = 25000000;
+	mmc->voltages = host->voltages;
+	mmc->host_caps = host->host_caps;
+
+	mmc->b_max = DAVINCI_MAX_BLOCKS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/dw_mmc.c b/marvell/uboot/drivers/mmc/dw_mmc.c
new file mode 100644
index 0000000..4cec5aa
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/dw_mmc.c
@@ -0,0 +1,383 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ * Rajeshawari Shinde <rajeshwari.s@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <bouncebuf.h>
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <dwmmc.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,
+			       struct dwmci_idmac *cur_idmac,
+			       void *bounce_buffer)
+{
+	unsigned long ctrl;
+	unsigned int i = 0, flags, cnt, blk_cnt;
+	ulong data_start, data_end;
+
+
+	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);
+
+	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,
+				    (u32)bounce_buffer + (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;
+	ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac,
+				 data ? DIV_ROUND_UP(data->blocks, 8) : 0);
+	int flags = 0, i;
+	unsigned int timeout = 100000;
+	u32 retry = 10000;
+	u32 mask, ctrl;
+	ulong start = get_timer(0);
+	struct bounce_buffer bbstate;
+
+	while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
+		if (get_timer(start) > timeout) {
+			printf("Timeout on data busy\n");
+			return TIMEOUT;
+		}
+	}
+
+	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
+
+	if (data) {
+		if (data->flags == MMC_DATA_READ) {
+			bounce_buffer_start(&bbstate, (void*)data->dest,
+					    data->blocksize *
+					    data->blocks, GEN_BB_WRITE);
+		} else {
+			bounce_buffer_start(&bbstate, (void*)data->src,
+					    data->blocksize *
+					    data->blocks, GEN_BB_READ);
+		}
+		dwmci_prepare_data(host, data, cur_idmac,
+				   bbstate.bounce_buffer);
+	}
+
+	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);
+
+		bounce_buffer_stop(&bbstate);
+	}
+
+	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) || (freq == 0))
+		return 0;
+	/*
+	 * If host->get_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->get_mmc_clk)
+		sclk = host->get_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;
+
+	if (host->board_init)
+		host->board_init(host);
+
+	dwmci_writel(host, DWMCI_PWREN, 1);
+
+	if (!dwmci_wait_reset(host, DWMCI_RESET_ALL)) {
+		debug("%s[%d] Fail-reset!!\n",__func__,__LINE__);
+		return -1;
+	}
+
+	/* Enumerate at 400KHz */
+	dwmci_setup_bus(host, mmc->f_min);
+
+	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);
+
+	if (host->fifoth_val) {
+		dwmci_writel(host, DWMCI_FIFOTH, host->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 = calloc(sizeof(struct mmc), 1);
+	if (!mmc) {
+		printf("mmc calloc 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/marvell/uboot/drivers/mmc/exynos_dw_mmc.c b/marvell/uboot/drivers/mmc/exynos_dw_mmc.c
new file mode 100644
index 0000000..b3e5c5e
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/exynos_dw_mmc.c
@@ -0,0 +1,168 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dwmmc.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <asm/arch/dwmmc.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/pinmux.h>
+
+#define	DWMMC_MAX_CH_NUM		4
+#define	DWMMC_MAX_FREQ			52000000
+#define	DWMMC_MIN_FREQ			400000
+#define	DWMMC_MMC0_CLKSEL_VAL		0x03030001
+#define	DWMMC_MMC2_CLKSEL_VAL		0x03020001
+
+/*
+ * Function used as callback function to initialise the
+ * CLKSEL register for every mmc channel.
+ */
+static void exynos_dwmci_clksel(struct dwmci_host *host)
+{
+	dwmci_writel(host, DWMCI_CLKSEL, host->clksel_val);
+}
+
+unsigned int exynos_dwmci_get_clk(int dev_index)
+{
+	return get_mmc_clk(dev_index);
+}
+
+static void exynos_dwmci_board_init(struct dwmci_host *host)
+{
+	if (host->quirks & DWMCI_QUIRK_DISABLE_SMU) {
+		dwmci_writel(host, EMMCP_MPSBEGIN0, 0);
+		dwmci_writel(host, EMMCP_SEND0, 0);
+		dwmci_writel(host, EMMCP_CTRL0,
+			     MPSCTRL_SECURE_READ_BIT |
+			     MPSCTRL_SECURE_WRITE_BIT |
+			     MPSCTRL_NON_SECURE_READ_BIT |
+			     MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID);
+	}
+}
+
+/*
+ * This function adds the mmc channel to be registered with mmc core.
+ * index -	mmc channel number.
+ * regbase -	register base address of mmc channel specified in 'index'.
+ * bus_width -	operating bus width of mmc channel specified in 'index'.
+ * clksel -	value to be written into CLKSEL register in case of FDT.
+ *		NULL in case od non-FDT.
+ */
+int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
+{
+	struct dwmci_host *host = NULL;
+	unsigned int div;
+	unsigned long freq, sclk;
+	host = malloc(sizeof(struct dwmci_host));
+	if (!host) {
+		printf("dwmci_host malloc fail!\n");
+		return 1;
+	}
+	/* request mmc clock vlaue of 52MHz.  */
+	freq = 52000000;
+	sclk = get_mmc_clk(index);
+	div = DIV_ROUND_UP(sclk, freq);
+	/* set the clock divisor for mmc */
+	set_mmc_clk(index, div);
+
+	host->name = "EXYNOS DWMMC";
+	host->ioaddr = (void *)regbase;
+	host->buswidth = bus_width;
+#ifdef CONFIG_EXYNOS5420
+	host->quirks = DWMCI_QUIRK_DISABLE_SMU;
+#endif
+	host->board_init = exynos_dwmci_board_init;
+
+	if (clksel) {
+		host->clksel_val = clksel;
+	} else {
+		if (0 == index)
+			host->clksel_val = DWMMC_MMC0_CLKSEL_VAL;
+		if (2 == index)
+			host->clksel_val = DWMMC_MMC2_CLKSEL_VAL;
+	}
+
+	host->clksel = exynos_dwmci_clksel;
+	host->dev_index = index;
+	host->get_mmc_clk = exynos_dwmci_get_clk;
+	/* Add the mmc channel to be registered with mmc core */
+	if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
+		debug("dwmmc%d registration failed\n", index);
+		return -1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_OF_CONTROL
+int exynos_dwmmc_init(const void *blob)
+{
+	int index, bus_width;
+	int node_list[DWMMC_MAX_CH_NUM];
+	int err = 0, dev_id, flag, count, i;
+	u32 clksel_val, base, timing[3];
+
+	count = fdtdec_find_aliases_for_id(blob, "mmc",
+				COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list,
+				DWMMC_MAX_CH_NUM);
+
+	for (i = 0; i < count; i++) {
+		int node = node_list[i];
+
+		if (node <= 0)
+			continue;
+
+		/* Extract device id for each mmc channel */
+		dev_id = pinmux_decode_periph_id(blob, node);
+
+		/* Get the bus width from the device node */
+		bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
+		if (bus_width <= 0) {
+			debug("DWMMC: Can't get bus-width\n");
+			return -1;
+		}
+		if (8 == bus_width)
+			flag = PINMUX_FLAG_8BIT_MODE;
+		else
+			flag = PINMUX_FLAG_NONE;
+
+		/* config pinmux for each mmc channel */
+		err = exynos_pinmux_config(dev_id, flag);
+		if (err) {
+			debug("DWMMC not configured\n");
+			return err;
+		}
+
+		index = dev_id - PERIPH_ID_SDMMC0;
+
+		/* Get the base address from the device node */
+		base = fdtdec_get_addr(blob, node, "reg");
+		if (!base) {
+			debug("DWMMC: Can't get base address\n");
+			return -1;
+		}
+		/* Extract the timing info from the node */
+		err = fdtdec_get_int_array(blob, node, "samsung,timing",
+					timing, 3);
+		if (err) {
+			debug("Can't get sdr-timings for divider\n");
+			return -1;
+		}
+
+		clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
+				DWMCI_SET_DRV_CLK(timing[1]) |
+				DWMCI_SET_DIV_RATIO(timing[2]));
+		/* Initialise each mmc channel */
+		err = exynos_dwmci_add_port(index, base, bus_width, clksel_val);
+		if (err)
+			debug("dwmmc Channel-%d init failed\n", index);
+	}
+	return 0;
+}
+#endif
diff --git a/marvell/uboot/drivers/mmc/fsl_esdhc.c b/marvell/uboot/drivers/mmc/fsl_esdhc.c
new file mode 100644
index 0000000..e3cd0c7
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/fsl_esdhc.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the pxa mmc code:
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <hwconfig.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <fsl_esdhc.h>
+#include <fdt_support.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct fsl_esdhc {
+	uint    dsaddr;		/* SDMA system address register */
+	uint    blkattr;	/* Block attributes register */
+	uint    cmdarg;		/* Command argument register */
+	uint    xfertyp;	/* Transfer type register */
+	uint    cmdrsp0;	/* Command response 0 register */
+	uint    cmdrsp1;	/* Command response 1 register */
+	uint    cmdrsp2;	/* Command response 2 register */
+	uint    cmdrsp3;	/* Command response 3 register */
+	uint    datport;	/* Buffer data port register */
+	uint    prsstat;	/* Present state register */
+	uint    proctl;		/* Protocol control register */
+	uint    sysctl;		/* System Control Register */
+	uint    irqstat;	/* Interrupt status register */
+	uint    irqstaten;	/* Interrupt status enable register */
+	uint    irqsigen;	/* Interrupt signal enable register */
+	uint    autoc12err;	/* Auto CMD error status register */
+	uint    hostcapblt;	/* Host controller capabilities register */
+	uint    wml;		/* Watermark level register */
+	uint    mixctrl;	/* For USDHC */
+	char    reserved1[4];	/* reserved */
+	uint    fevt;		/* Force event register */
+	uint    admaes;		/* ADMA error status register */
+	uint    adsaddr;	/* ADMA system address register */
+	char    reserved2[160];	/* reserved */
+	uint    hostver;	/* Host controller version register */
+	char    reserved3[4];	/* reserved */
+	uint    dmaerraddr;	/* DMA error address register */
+	char    reserved4[4];	/* reserved */
+	uint    dmaerrattr;	/* DMA error attribute register */
+	char    reserved5[4];	/* reserved */
+	uint    hostcapblt2;	/* Host controller capabilities register 2 */
+	char    reserved6[8];	/* reserved */
+	uint    tcr;		/* Tuning control register */
+	char    reserved7[28];	/* reserved */
+	uint    sddirctl;	/* SD direction control register */
+	char    reserved8[712];	/* reserved */
+	uint    scr;		/* eSDHC control register */
+};
+
+/* Return the XFERTYP flags for a given command and data packet */
+static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	uint xfertyp = 0;
+
+	if (data) {
+		xfertyp |= XFERTYP_DPSEL;
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+		xfertyp |= XFERTYP_DMAEN;
+#endif
+		if (data->blocks > 1) {
+			xfertyp |= XFERTYP_MSBSEL;
+			xfertyp |= XFERTYP_BCEN;
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
+			xfertyp |= XFERTYP_AC12EN;
+#endif
+		}
+
+		if (data->flags & MMC_DATA_READ)
+			xfertyp |= XFERTYP_DTDSEL;
+	}
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		xfertyp |= XFERTYP_CCCEN;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		xfertyp |= XFERTYP_CICEN;
+	if (cmd->resp_type & MMC_RSP_136)
+		xfertyp |= XFERTYP_RSPTYP_136;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		xfertyp |= XFERTYP_RSPTYP_48_BUSY;
+	else if (cmd->resp_type & MMC_RSP_PRESENT)
+		xfertyp |= XFERTYP_RSPTYP_48;
+
+#if defined(CONFIG_MX53) || defined(CONFIG_T4240QDS)
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		xfertyp |= XFERTYP_CMDTYP_ABORT;
+#endif
+	return XFERTYP_CMD(cmd->cmdidx) | xfertyp;
+}
+
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
+/*
+ * PIO Read/Write Mode reduce the performace as DMA is not used in this mode.
+ */
+static void
+esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data)
+{
+	struct fsl_esdhc_cfg *cfg = mmc->priv;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+	uint blocks;
+	char *buffer;
+	uint databuf;
+	uint size;
+	uint irqstat;
+	uint timeout;
+
+	if (data->flags & MMC_DATA_READ) {
+		blocks = data->blocks;
+		buffer = data->dest;
+		while (blocks) {
+			timeout = PIO_TIMEOUT;
+			size = data->blocksize;
+			irqstat = esdhc_read32(&regs->irqstat);
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
+				&& --timeout);
+			if (timeout <= 0) {
+				printf("\nData Read Failed in PIO Mode.");
+				return;
+			}
+			while (size && (!(irqstat & IRQSTAT_TC))) {
+				udelay(100); /* Wait before last byte transfer complete */
+				irqstat = esdhc_read32(&regs->irqstat);
+				databuf = in_le32(&regs->datport);
+				*((uint *)buffer) = databuf;
+				buffer += 4;
+				size -= 4;
+			}
+			blocks--;
+		}
+	} else {
+		blocks = data->blocks;
+		buffer = (char *)data->src;
+		while (blocks) {
+			timeout = PIO_TIMEOUT;
+			size = data->blocksize;
+			irqstat = esdhc_read32(&regs->irqstat);
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)
+				&& --timeout);
+			if (timeout <= 0) {
+				printf("\nData Write Failed in PIO Mode.");
+				return;
+			}
+			while (size && (!(irqstat & IRQSTAT_TC))) {
+				udelay(100); /* Wait before last byte transfer complete */
+				databuf = *((uint *)buffer);
+				buffer += 4;
+				size -= 4;
+				irqstat = esdhc_read32(&regs->irqstat);
+				out_le32(&regs->datport, databuf);
+			}
+			blocks--;
+		}
+	}
+}
+#endif
+
+static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
+{
+	int timeout;
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+	uint wml_value;
+
+	wml_value = data->blocksize/4;
+
+	if (data->flags & MMC_DATA_READ) {
+		if (wml_value > WML_RD_WML_MAX)
+			wml_value = WML_RD_WML_MAX_VAL;
+
+		esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
+		esdhc_write32(&regs->dsaddr, (u32)data->dest);
+	} else {
+		flush_dcache_range((ulong)data->src,
+				   (ulong)data->src+data->blocks
+					 *data->blocksize);
+
+		if (wml_value > WML_WR_WML_MAX)
+			wml_value = WML_WR_WML_MAX_VAL;
+		if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
+			printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
+			return TIMEOUT;
+		}
+
+		esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
+					wml_value << 16);
+		esdhc_write32(&regs->dsaddr, (u32)data->src);
+	}
+#else	/* CONFIG_SYS_FSL_ESDHC_USE_PIO */
+	if (!(data->flags & MMC_DATA_READ)) {
+		if ((esdhc_read32(&regs->prsstat) & PRSSTAT_WPSPL) == 0) {
+			printf("\nThe SD card is locked. "
+				"Can not write to a locked card.\n\n");
+			return TIMEOUT;
+		}
+		esdhc_write32(&regs->dsaddr, (u32)data->src);
+	} else
+		esdhc_write32(&regs->dsaddr, (u32)data->dest);
+#endif	/* CONFIG_SYS_FSL_ESDHC_USE_PIO */
+
+	esdhc_write32(&regs->blkattr, data->blocks << 16 | data->blocksize);
+
+	/* Calculate the timeout period for data transactions */
+	/*
+	 * 1)Timeout period = (2^(timeout+13)) SD Clock cycles
+	 * 2)Timeout period should be minimum 0.250sec as per SD Card spec
+	 *  So, Number of SD Clock cycles for 0.25sec should be minimum
+	 *		(SD Clock/sec * 0.25 sec) SD Clock cycles
+	 *		= (mmc->tran_speed * 1/4) SD Clock cycles
+	 * As 1) >=  2)
+	 * => (2^(timeout+13)) >= mmc->tran_speed * 1/4
+	 * Taking log2 both the sides
+	 * => timeout + 13 >= log2(mmc->tran_speed/4)
+	 * Rounding up to next power of 2
+	 * => timeout + 13 = log2(mmc->tran_speed/4) + 1
+	 * => timeout + 13 = fls(mmc->tran_speed/4)
+	 */
+	timeout = fls(mmc->tran_speed/4);
+	timeout -= 13;
+
+	if (timeout > 14)
+		timeout = 14;
+
+	if (timeout < 0)
+		timeout = 0;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A001
+	if ((timeout == 4) || (timeout == 8) || (timeout == 12))
+		timeout++;
+#endif
+
+	esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, timeout << 16);
+
+	return 0;
+}
+
+static void check_and_invalidate_dcache_range
+	(struct mmc_cmd *cmd,
+	 struct mmc_data *data) {
+	unsigned start = (unsigned)data->dest ;
+	unsigned size = roundup(ARCH_DMA_MINALIGN,
+				data->blocks*data->blocksize);
+	unsigned end = start+size ;
+	invalidate_dcache_range(start, end);
+}
+/*
+ * Sends a command out on the bus.  Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	uint	xfertyp;
+	uint	irqstat;
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		return 0;
+#endif
+
+	esdhc_write32(&regs->irqstat, -1);
+
+	sync();
+
+	/* Wait for the bus to be idle */
+	while ((esdhc_read32(&regs->prsstat) & PRSSTAT_CICHB) ||
+			(esdhc_read32(&regs->prsstat) & PRSSTAT_CIDHB))
+		;
+
+	while (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA)
+		;
+
+	/* Wait at least 8 SD clock cycles before the next command */
+	/*
+	 * Note: This is way more than 8 cycles, but 1ms seems to
+	 * resolve timing issues with some cards
+	 */
+	udelay(1000);
+
+	/* Set up for a data transfer if we have one */
+	if (data) {
+		int err;
+
+		err = esdhc_setup_data(mmc, data);
+		if(err)
+			return err;
+	}
+
+	/* Figure out the transfer arguments */
+	xfertyp = esdhc_xfertyp(cmd, data);
+
+	/* Mask all irqs */
+	esdhc_write32(&regs->irqsigen, 0);
+
+	/* Send the command */
+	esdhc_write32(&regs->cmdarg, cmd->cmdarg);
+#if defined(CONFIG_FSL_USDHC)
+	esdhc_write32(&regs->mixctrl,
+	(esdhc_read32(&regs->mixctrl) & 0xFFFFFF80) | (xfertyp & 0x7F));
+	esdhc_write32(&regs->xfertyp, xfertyp & 0xFFFF0000);
+#else
+	esdhc_write32(&regs->xfertyp, xfertyp);
+#endif
+
+	/* Wait for the command to complete */
+	while (!(esdhc_read32(&regs->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE)))
+		;
+
+	irqstat = esdhc_read32(&regs->irqstat);
+
+	/* Reset CMD and DATA portions on error */
+	if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) {
+		esdhc_write32(&regs->sysctl, esdhc_read32(&regs->sysctl) |
+			      SYSCTL_RSTC);
+		while (esdhc_read32(&regs->sysctl) & SYSCTL_RSTC)
+			;
+
+		if (data) {
+			esdhc_write32(&regs->sysctl,
+				      esdhc_read32(&regs->sysctl) |
+				      SYSCTL_RSTD);
+			while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTD))
+				;
+		}
+	}
+
+	if (irqstat & CMD_ERR)
+		return COMM_ERR;
+
+	if (irqstat & IRQSTAT_CTOE)
+		return TIMEOUT;
+
+	/* Workaround for ESDHC errata ENGcm03648 */
+	if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
+		int timeout = 2500;
+
+		/* Poll on DATA0 line for cmd with busy signal for 250 ms */
+		while (timeout > 0 && !(esdhc_read32(&regs->prsstat) &
+					PRSSTAT_DAT0)) {
+			udelay(100);
+			timeout--;
+		}
+
+		if (timeout <= 0) {
+			printf("Timeout waiting for DAT0 to go high!\n");
+			return TIMEOUT;
+		}
+	}
+
+	/* Copy the response to the response buffer */
+	if (cmd->resp_type & MMC_RSP_136) {
+		u32 cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
+
+		cmdrsp3 = esdhc_read32(&regs->cmdrsp3);
+		cmdrsp2 = esdhc_read32(&regs->cmdrsp2);
+		cmdrsp1 = esdhc_read32(&regs->cmdrsp1);
+		cmdrsp0 = esdhc_read32(&regs->cmdrsp0);
+		cmd->response[0] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
+		cmd->response[1] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
+		cmd->response[2] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
+		cmd->response[3] = (cmdrsp0 << 8);
+	} else
+		cmd->response[0] = esdhc_read32(&regs->cmdrsp0);
+
+	/* Wait until all of the blocks are transferred */
+	if (data) {
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
+		esdhc_pio_read_write(mmc, data);
+#else
+		do {
+			irqstat = esdhc_read32(&regs->irqstat);
+
+			if (irqstat & IRQSTAT_DTOE)
+				return TIMEOUT;
+
+			if (irqstat & DATA_ERR)
+				return COMM_ERR;
+		} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
+#endif
+		if (data->flags & MMC_DATA_READ)
+			check_and_invalidate_dcache_range(cmd, data);
+	}
+
+	esdhc_write32(&regs->irqstat, -1);
+
+	return 0;
+}
+
+static void set_sysctl(struct mmc *mmc, uint clock)
+{
+	int div, pre_div;
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+	int sdhc_clk = cfg->sdhc_clk;
+	uint clk;
+
+	if (clock < mmc->f_min)
+		clock = mmc->f_min;
+
+	if (sdhc_clk / 16 > clock) {
+		for (pre_div = 2; pre_div < 256; pre_div *= 2)
+			if ((sdhc_clk / pre_div) <= (clock * 16))
+				break;
+	} else
+		pre_div = 2;
+
+	for (div = 1; div <= 16; div++)
+		if ((sdhc_clk / (div * pre_div)) <= clock)
+			break;
+
+	pre_div >>= 1;
+	div -= 1;
+
+	clk = (pre_div << 8) | (div << 4);
+
+	esdhc_clrbits32(&regs->sysctl, SYSCTL_CKEN);
+
+	esdhc_clrsetbits32(&regs->sysctl, SYSCTL_CLOCK_MASK, clk);
+
+	udelay(10000);
+
+	clk = SYSCTL_PEREN | SYSCTL_CKEN;
+
+	esdhc_setbits32(&regs->sysctl, clk);
+}
+
+static void esdhc_set_ios(struct mmc *mmc)
+{
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+
+	/* Set the clock speed */
+	set_sysctl(mmc, mmc->clock);
+
+	/* Set the bus width */
+	esdhc_clrbits32(&regs->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
+
+	if (mmc->bus_width == 4)
+		esdhc_setbits32(&regs->proctl, PROCTL_DTW_4);
+	else if (mmc->bus_width == 8)
+		esdhc_setbits32(&regs->proctl, PROCTL_DTW_8);
+
+}
+
+static int esdhc_init(struct mmc *mmc)
+{
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+	int timeout = 1000;
+
+	/* Reset the entire host controller */
+	esdhc_setbits32(&regs->sysctl, SYSCTL_RSTA);
+
+	/* Wait until the controller is available */
+	while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
+		udelay(1000);
+
+#ifndef ARCH_MXC
+	/* Enable cache snooping */
+	esdhc_write32(&regs->scr, 0x00000040);
+#endif
+
+	esdhc_setbits32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
+
+	/* Set the initial clock speed */
+	mmc_set_clock(mmc, 400000);
+
+	/* Disable the BRR and BWR bits in IRQSTAT */
+	esdhc_clrbits32(&regs->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
+
+	/* Put the PROCTL reg back to the default */
+	esdhc_write32(&regs->proctl, PROCTL_INIT);
+
+	/* Set timout to the maximum value */
+	esdhc_clrsetbits32(&regs->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16);
+
+	return 0;
+}
+
+static int esdhc_getcd(struct mmc *mmc)
+{
+	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
+	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
+	int timeout = 1000;
+
+	while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
+		udelay(1000);
+
+	return timeout > 0;
+}
+
+static void esdhc_reset(struct fsl_esdhc *regs)
+{
+	unsigned long timeout = 100; /* wait max 100 ms */
+
+	/* reset the controller */
+	esdhc_setbits32(&regs->sysctl, SYSCTL_RSTA);
+
+	/* hardware clears the bit when it is done */
+	while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
+		udelay(1000);
+	if (!timeout)
+		printf("MMC/SD: Reset never completed.\n");
+}
+
+int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
+{
+	struct fsl_esdhc *regs;
+	struct mmc *mmc;
+	u32 caps, voltage_caps;
+
+	if (!cfg)
+		return -1;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+
+	memset(mmc, 0, sizeof(struct mmc));
+	sprintf(mmc->name, "FSL_SDHC");
+	regs = (struct fsl_esdhc *)cfg->esdhc_base;
+
+	/* First reset the eSDHC controller */
+	esdhc_reset(regs);
+
+	esdhc_setbits32(&regs->sysctl, SYSCTL_PEREN | SYSCTL_HCKEN
+				| SYSCTL_IPGEN | SYSCTL_CKEN);
+
+	mmc->priv = cfg;
+	mmc->send_cmd = esdhc_send_cmd;
+	mmc->set_ios = esdhc_set_ios;
+	mmc->init = esdhc_init;
+	mmc->getcd = esdhc_getcd;
+	mmc->getwp = NULL;
+
+	voltage_caps = 0;
+	caps = regs->hostcapblt;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135
+	caps = caps & ~(ESDHC_HOSTCAPBLT_SRS |
+			ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30);
+#endif
+
+/* T4240 host controller capabilities register should have VS33 bit */
+#ifdef CONFIG_SYS_FSL_MMC_HAS_CAPBLT_VS33
+	caps = caps | ESDHC_HOSTCAPBLT_VS33;
+#endif
+
+	if (caps & ESDHC_HOSTCAPBLT_VS18)
+		voltage_caps |= MMC_VDD_165_195;
+	if (caps & ESDHC_HOSTCAPBLT_VS30)
+		voltage_caps |= MMC_VDD_29_30 | MMC_VDD_30_31;
+	if (caps & ESDHC_HOSTCAPBLT_VS33)
+		voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+#ifdef CONFIG_SYS_SD_VOLTAGE
+	mmc->voltages = CONFIG_SYS_SD_VOLTAGE;
+#else
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+#endif
+	if ((mmc->voltages & voltage_caps) == 0) {
+		printf("voltage not supported by controller\n");
+		return -1;
+	}
+
+	mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HC;
+
+	if (cfg->max_bus_width > 0) {
+		if (cfg->max_bus_width < 8)
+			mmc->host_caps &= ~MMC_MODE_8BIT;
+		if (cfg->max_bus_width < 4)
+			mmc->host_caps &= ~MMC_MODE_4BIT;
+	}
+
+	if (caps & ESDHC_HOSTCAPBLT_HSS)
+		mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+	mmc->f_min = 400000;
+	mmc->f_max = MIN(gd->arch.sdhc_clk, 52000000);
+
+	mmc->b_max = 0;
+	mmc_register(mmc);
+
+	return 0;
+}
+
+int fsl_esdhc_mmc_init(bd_t *bis)
+{
+	struct fsl_esdhc_cfg *cfg;
+
+	cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1);
+	cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR;
+	cfg->sdhc_clk = gd->arch.sdhc_clk;
+	return fsl_esdhc_initialize(bis, cfg);
+}
+
+#ifdef CONFIG_OF_LIBFDT
+void fdt_fixup_esdhc(void *blob, bd_t *bd)
+{
+	const char *compat = "fsl,esdhc";
+
+#ifdef CONFIG_FSL_ESDHC_PIN_MUX
+	if (!hwconfig("esdhc")) {
+		do_fixup_by_compat(blob, compat, "status", "disabled",
+				8 + 1, 1);
+		return;
+	}
+#endif
+
+	do_fixup_by_compat_u32(blob, compat, "clock-frequency",
+			       gd->arch.sdhc_clk, 1);
+
+	do_fixup_by_compat(blob, compat, "status", "okay",
+			   4 + 1, 1);
+}
+#endif
diff --git a/marvell/uboot/drivers/mmc/fsl_esdhc_spl.c b/marvell/uboot/drivers/mmc/fsl_esdhc_spl.c
new file mode 100644
index 0000000..8fc263f
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/fsl_esdhc_spl.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <malloc.h>
+
+/*
+ * The environment variables are written to just after the u-boot image
+ * on SDCard, so we must read the MBR to get the start address and code
+ * length of the u-boot image, then calculate the address of the env.
+ */
+#define ESDHC_BOOT_IMAGE_SIZE	0x48
+#define ESDHC_BOOT_IMAGE_ADDR	0x50
+#define MBRDBR_BOOT_SIG_55	0x1fe
+#define MBRDBR_BOOT_SIG_AA	0x1ff
+#define CONFIG_CFG_DATA_SECTOR	0
+
+/*
+ * The main entry for mmc booting. It's necessary that SDRAM is already
+ * configured and available since this code loads the main U-Boot image
+ * from mmc into SDRAM and starts it from there.
+ */
+
+void __noreturn mmc_boot(void)
+{
+	__attribute__((noreturn)) void (*uboot)(void);
+	uint blk_start, blk_cnt, err;
+	u32 blklen;
+	uchar *tmp_buf;
+	uchar val;
+	uint i, byte_num;
+	u32 offset, code_len;
+	struct mmc *mmc;
+
+	mmc = find_mmc_device(0);
+	if (!mmc) {
+		puts("spl: mmc device not found!!\n");
+		hang();
+	}
+
+#ifdef CONFIG_FSL_CORENET
+	offset = CONFIG_SYS_MMC_U_BOOT_OFFS;
+	code_len = CONFIG_SYS_MMC_U_BOOT_SIZE;
+#else
+	blklen = mmc->read_bl_len;
+	tmp_buf = malloc(blklen);
+	if (!tmp_buf) {
+		puts("spl: malloc memory failed!!\n");
+		hang();
+	}
+	memset(tmp_buf, 0, blklen);
+
+	/*
+	* Read source addr from sd card
+	*/
+	err = mmc->block_dev.block_read(0, CONFIG_CFG_DATA_SECTOR, 1, tmp_buf);
+	if (err != 1) {
+		puts("spl: mmc read failed!!\n");
+		free(tmp_buf);
+		hang();
+	}
+
+	val = *(tmp_buf + MBRDBR_BOOT_SIG_55);
+	if (0x55 != val) {
+		puts("spl: mmc signature is not valid!!\n");
+		free(tmp_buf);
+		hang();
+	}
+	val = *(tmp_buf + MBRDBR_BOOT_SIG_AA);
+	if (0xAA != val) {
+		puts("spl: mmc signature is not valid!!\n");
+		free(tmp_buf);
+		hang();
+	}
+
+	byte_num = 4;
+	offset = 0;
+	for (i = 0; i < byte_num; i++) {
+		val = *(tmp_buf + ESDHC_BOOT_IMAGE_ADDR + i);
+		offset = (offset << 8) + val;
+	}
+	offset += CONFIG_SYS_MMC_U_BOOT_OFFS;
+	/* Get the code size from offset 0x48 */
+	byte_num = 4;
+	code_len = 0;
+	for (i = 0; i < byte_num; i++) {
+		val = *(tmp_buf + ESDHC_BOOT_IMAGE_SIZE + i);
+		code_len = (code_len << 8) + val;
+	}
+	code_len -= CONFIG_SYS_MMC_U_BOOT_OFFS;
+	/*
+	* Load U-Boot image from mmc into RAM
+	*/
+#endif
+	blk_start = ALIGN(offset, mmc->read_bl_len) / mmc->read_bl_len;
+	blk_cnt = ALIGN(code_len, mmc->read_bl_len) / mmc->read_bl_len;
+	err = mmc->block_dev.block_read(0, blk_start, blk_cnt,
+					(uchar *)CONFIG_SYS_MMC_U_BOOT_DST);
+	if (err != blk_cnt) {
+		puts("spl: mmc read failed!!\n");
+		free(tmp_buf);
+		hang();
+	}
+
+	/*
+	* Clean d-cache and invalidate i-cache, to
+	* make sure that no stale data is executed.
+	*/
+	flush_cache(CONFIG_SYS_MMC_U_BOOT_DST, CONFIG_SYS_MMC_U_BOOT_SIZE);
+
+	/*
+	* Jump to U-Boot image
+	*/
+	uboot = (void *)CONFIG_SYS_MMC_U_BOOT_START;
+	(*uboot)();
+}
diff --git a/marvell/uboot/drivers/mmc/ftsdc010_mci.c b/marvell/uboot/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..7600d5c
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,380 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+
+struct ftsdc010_chip {
+	void __iomem *regs;
+	uint32_t wprot;   /* write protected (locked) */
+	uint32_t rate;    /* actual SD clock in Hz */
+	uint32_t sclk;    /* FTSDC010 source clock in Hz */
+	uint32_t fifo;    /* fifo depth in bytes */
+	uint32_t acmd;
+};
+
+static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	int ret = TIMEOUT;
+	uint32_t ts, st;
+	uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+	uint32_t arg   = mmc_cmd->cmdarg;
+	uint32_t flags = mmc_cmd->resp_type;
+
+	cmd |= FTSDC010_CMD_CMD_EN;
+
+	if (chip->acmd) {
+		cmd |= FTSDC010_CMD_APP_CMD;
+		chip->acmd = 0;
+	}
+
+	if (flags & MMC_RSP_PRESENT)
+		cmd |= FTSDC010_CMD_NEED_RSP;
+
+	if (flags & MMC_RSP_136)
+		cmd |= FTSDC010_CMD_LONG_RSP;
+
+	writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+		&regs->clr);
+	writel(arg, &regs->argu);
+	writel(cmd, &regs->cmd);
+
+	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+			if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+				writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+				ret = 0;
+				break;
+			}
+		}
+	} else {
+		st = 0;
+		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+			st = readl(&regs->status);
+			writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+			if (st & FTSDC010_STATUS_RSP_MASK)
+				break;
+		}
+		if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+			if (flags & MMC_RSP_136) {
+				mmc_cmd->response[0] = readl(&regs->rsp3);
+				mmc_cmd->response[1] = readl(&regs->rsp2);
+				mmc_cmd->response[2] = readl(&regs->rsp1);
+				mmc_cmd->response[3] = readl(&regs->rsp0);
+			} else {
+				mmc_cmd->response[0] = readl(&regs->rsp0);
+			}
+			ret = 0;
+		} else {
+			debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+				mmc_cmd->cmdidx, st);
+		}
+	}
+
+	if (ret) {
+		debug("ftsdc010: cmd timeout (op code=%d)\n",
+			mmc_cmd->cmdidx);
+	} else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+		chip->acmd = 1;
+	}
+
+	return ret;
+}
+
+static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	uint32_t div;
+
+	for (div = 0; div < 0x7f; ++div) {
+		if (rate >= chip->sclk / (2 * (div + 1)))
+			break;
+	}
+	chip->rate = chip->sclk / (2 * (div + 1));
+
+	writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+	if (IS_SD(mmc)) {
+		setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
+
+		if (chip->rate > 25000000)
+			setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+		else
+			clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+	}
+}
+
+static inline int ftsdc010_is_ro(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+	return chip->wprot || (csd[1] & 0x30);
+}
+
+static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
+{
+	int ret = TIMEOUT;
+	uint32_t st, ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		st = readl(&regs->status);
+		if (!(st & mask))
+			continue;
+		writel(st & mask, &regs->clr);
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+
+	return ret;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
+	struct mmc_data *data)
+{
+	int ret = UNUSABLE_ERR;
+	uint32_t len = 0;
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+		printf("ftsdc010: the card is write protected!\n");
+		return ret;
+	}
+
+	if (data) {
+		uint32_t dcr;
+
+		len = data->blocksize * data->blocks;
+
+		/* 1. data disable + fifo reset */
+		dcr = 0;
+#ifdef CONFIG_FTSDC010_SDIO
+		dcr |= FTSDC010_DCR_FIFO_RST;
+#endif
+		writel(dcr, &regs->dcr);
+
+		/* 2. clear status register */
+		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+			| FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+		/* 3. data timeout (1 sec) */
+		writel(chip->rate, &regs->dtr);
+
+		/* 4. data length (bytes) */
+		writel(len, &regs->dlr);
+
+		/* 5. data enable */
+		dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			dcr |= FTSDC010_DCR_DATA_WRITE;
+		writel(dcr, &regs->dcr);
+	}
+
+	ret = ftsdc010_send_cmd(mmc, cmd);
+	if (ret) {
+		printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
+		return ret;
+	}
+
+	if (!data)
+		return ret;
+
+	if (data->flags & MMC_DATA_WRITE) {
+		const uint8_t *buf = (const uint8_t *)data->src;
+
+		while (len > 0) {
+			int wlen;
+
+			/* wait for tx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
+			if (ret)
+				break;
+
+			/* write bytes to ftsdc010 */
+			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+				writel(*(uint32_t *)buf, &regs->dwr);
+				buf  += 4;
+				wlen += 4;
+			}
+
+			len -= wlen;
+		}
+
+	} else {
+		uint8_t *buf = (uint8_t *)data->dest;
+
+		while (len > 0) {
+			int rlen;
+
+			/* wait for rx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
+			if (ret)
+				break;
+
+			/* fetch bytes from ftsdc010 */
+			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+				*(uint32_t *)buf = readl(&regs->dwr);
+				buf  += 4;
+				rlen += 4;
+			}
+
+			len -= rlen;
+		}
+
+	}
+
+	if (!ret) {
+		ret = ftsdc010_wait(regs,
+			FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+	}
+
+	return ret;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	ftsdc010_clkset(mmc, mmc->clock);
+
+	clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
+	switch (mmc->bus_width) {
+	case 4:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
+		break;
+	case 8:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
+		break;
+	default:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
+		break;
+	}
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	uint32_t ts;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+		return NO_CARD_ERR;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+		printf("ftsdc010: write protected\n");
+		chip->wprot = 1;
+	}
+
+	chip->fifo = (readl(&regs->feature) & 0xff) << 2;
+
+	/* 1. chip reset */
+	writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+			continue;
+		break;
+	}
+	if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
+		printf("ftsdc010: reset failed\n");
+		return UNUSABLE_ERR;
+	}
+
+	/* 2. enter low speed mode (400k card detection) */
+	ftsdc010_clkset(mmc, 400000);
+
+	/* 3. interrupt disabled */
+	writel(0, &regs->int_mask);
+
+	return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+	struct mmc *mmc;
+	struct ftsdc010_chip *chip;
+	struct ftsdc010_mmc __iomem *regs;
+#ifdef CONFIG_FTSDC010_BASE_LIST
+	uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
+
+	if (devid < 0 || devid >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[devid];
+#else
+	regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
+#endif
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+	memset(mmc, 0, sizeof(struct mmc));
+
+	chip = malloc(sizeof(struct ftsdc010_chip));
+	if (!chip) {
+		free(mmc);
+		return -ENOMEM;
+	}
+	memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+	chip->regs = regs;
+	mmc->priv  = chip;
+
+	sprintf(mmc->name, "ftsdc010");
+	mmc->send_cmd  = ftsdc010_request;
+	mmc->set_ios   = ftsdc010_set_ios;
+	mmc->init      = ftsdc010_init;
+
+	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+	switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+	case FTSDC010_BWR_CAPS_4BIT:
+		mmc->host_caps |= MMC_MODE_4BIT;
+		break;
+	case FTSDC010_BWR_CAPS_8BIT:
+		mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+		break;
+	default:
+		break;
+	}
+
+#ifdef CONFIG_SYS_CLK_FREQ
+	chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+	chip->sclk = clk_get_rate("SDC");
+#endif
+
+	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max     = chip->sclk / 2;
+	mmc->f_min     = chip->sclk / 0x100;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/ftsdc021_sdhci.c b/marvell/uboot/drivers/mmc/ftsdc021_sdhci.c
new file mode 100644
index 0000000..1f6cdba
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/ftsdc021_sdhci.c
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+
+#ifndef CONFIG_FTSDC021_CLOCK
+#define CONFIG_FTSDC021_CLOCK   clk_get_rate("MMC")
+#endif
+
+int ftsdc021_sdhci_init(u32 regbase)
+{
+	struct sdhci_host *host = NULL;
+	uint32_t freq = CONFIG_FTSDC021_CLOCK;
+
+	host = calloc(1, sizeof(struct sdhci_host));
+	if (!host) {
+		puts("sdh_host malloc fail!\n");
+		return 1;
+	}
+
+	host->name = "FTSDC021";
+	host->ioaddr = (void __iomem *)regbase;
+	host->quirks = 0;
+	add_sdhci(host, freq, 0);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/gen_atmel_mci.c b/marvell/uboot/drivers/mmc/gen_atmel_mci.c
new file mode 100644
index 0000000..c11dcd0
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/gen_atmel_mci.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2010
+ * Rob Emanuele <rob@emanuele.us>
+ * Reinhard Meyer, EMK Elektronik <reinhard.meyer@emk-elektronik.de>
+ *
+ * Original Driver:
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/hardware.h>
+#include "atmel_mci.h"
+
+#ifndef CONFIG_SYS_MMC_CLK_OD
+# define CONFIG_SYS_MMC_CLK_OD	150000
+#endif
+
+#define MMC_DEFAULT_BLKLEN	512
+
+#if defined(CONFIG_ATMEL_MCI_PORTB)
+# define MCI_BUS 1
+#else
+# define MCI_BUS 0
+#endif
+
+static int initialized = 0;
+
+/* Read Atmel MCI IP version */
+static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
+{
+	return readl(&mci->version) & 0x00000fff;
+}
+
+/*
+ * Print command and status:
+ *
+ * - always when DEBUG is defined
+ * - on command errors
+ */
+static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
+{
+	printf("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
+		cmdr, cmdr&0x3F, arg, status, msg);
+}
+
+/* Setup for MCI Clock and Block Size */
+static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
+{
+	atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+	u32 bus_hz = get_mci_clk_rate();
+	u32 clkdiv = 255;
+
+	debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n",
+		bus_hz, hz, blklen);
+	if (hz > 0) {
+		/* find lowest clkdiv yielding a rate <= than requested */
+		for (clkdiv=0; clkdiv<255; clkdiv++) {
+			if ((bus_hz / (clkdiv+1) / 2) <= hz)
+				break;
+		}
+	}
+	printf("mci: setting clock %u Hz, block size %u\n",
+		(bus_hz / (clkdiv+1)) / 2, blklen);
+
+	blklen &= 0xfffc;
+	/* On some platforms RDPROOF and WRPROOF are ignored */
+	writel((MMCI_BF(CLKDIV, clkdiv)
+		 | 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;
+}
+
+/* Return the CMDR with flags for a given command and data packet */
+static u32 mci_encode_cmd(
+	struct mmc_cmd *cmd, struct mmc_data *data, u32* error_flags)
+{
+	u32 cmdr = 0;
+
+	/* Default Flags for Errors */
+	*error_flags |= (MMCI_BIT(DTOE) | MMCI_BIT(RDIRE) | MMCI_BIT(RENDE) |
+		MMCI_BIT(RINDE) | MMCI_BIT(RTOE));
+
+	/* Default Flags for the Command */
+	cmdr |= MMCI_BIT(MAXLAT);
+
+	if (data) {
+		cmdr |= MMCI_BF(TRCMD, 1);
+		if (data->blocks > 1)
+			cmdr |= MMCI_BF(TRTYP, 1);
+		if (data->flags & MMC_DATA_READ)
+			cmdr |= MMCI_BIT(TRDIR);
+	}
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		*error_flags |= MMCI_BIT(RCRCE);
+	if (cmd->resp_type & MMC_RSP_136)
+		cmdr |= MMCI_BF(RSPTYP, 2);
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		cmdr |= MMCI_BF(RSPTYP, 3);
+	else if (cmd->resp_type & MMC_RSP_PRESENT)
+		cmdr |= MMCI_BF(RSPTYP, 1);
+
+	return cmdr | MMCI_BF(CMDNB, cmd->cmdidx);
+}
+
+/* Entered into function pointer in mci_send_cmd */
+static u32 mci_data_read(atmel_mci_t *mci, u32* data, u32 error_flags)
+{
+	u32 status;
+
+	do {
+		status = readl(&mci->sr);
+		if (status & (error_flags | MMCI_BIT(OVRE)))
+			goto io_fail;
+	} while (!(status & MMCI_BIT(RXRDY)));
+
+	if (status & MMCI_BIT(RXRDY)) {
+		*data = readl(&mci->rdr);
+		status = 0;
+	}
+io_fail:
+	return status;
+}
+
+/* Entered into function pointer in mci_send_cmd */
+static u32 mci_data_write(atmel_mci_t *mci, u32* data, u32 error_flags)
+{
+	u32 status;
+
+	do {
+		status = readl(&mci->sr);
+		if (status & (error_flags | MMCI_BIT(UNRE)))
+			goto io_fail;
+	} while (!(status & MMCI_BIT(TXRDY)));
+
+	if (status & MMCI_BIT(TXRDY)) {
+		writel(*data, &mci->tdr);
+		status = 0;
+	}
+io_fail:
+	return status;
+}
+
+/*
+ * Entered into mmc structure during driver init
+ *
+ * Sends a command out on the bus and deals with the block data.
+ * Takes the mmc pointer, a command pointer, and an optional data pointer.
+ */
+static int
+mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+	u32 cmdr;
+	u32 error_flags = 0;
+	u32 status;
+
+	if (!initialized) {
+		puts ("MCI not initialized!\n");
+		return COMM_ERR;
+	}
+
+	/* 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);
+
+#ifdef DEBUG
+	dump_cmd(cmdr, cmd->cmdarg, 0, "DEBUG");
+#endif
+
+	/* Wait for the command to complete */
+	while (!((status = readl(&mci->sr)) & MMCI_BIT(CMDRDY)));
+
+	if ((status & error_flags) & MMCI_BIT(RTOE)) {
+		dump_cmd(cmdr, cmd->cmdarg, status, "Command Time Out");
+		return TIMEOUT;
+	} else if (status & error_flags) {
+		dump_cmd(cmdr, cmd->cmdarg, status, "Command Failed");
+		return COMM_ERR;
+	}
+
+	/* Copy the response to the response buffer */
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = readl(&mci->rspr);
+		cmd->response[1] = readl(&mci->rspr1);
+		cmd->response[2] = readl(&mci->rspr2);
+		cmd->response[3] = readl(&mci->rspr3);
+	} else
+		cmd->response[0] = readl(&mci->rspr);
+
+	/* transfer all of the blocks */
+	if (data) {
+		u32 word_count, block_count;
+		u32* ioptr;
+		u32 sys_blocksize, dummy, i;
+		u32 (*mci_data_op)
+			(atmel_mci_t *mci, u32* data, u32 error_flags);
+
+		if (data->flags & MMC_DATA_READ) {
+			mci_data_op = mci_data_read;
+			sys_blocksize = mmc->read_bl_len;
+			ioptr = (u32*)data->dest;
+		} else {
+			mci_data_op = mci_data_write;
+			sys_blocksize = mmc->write_bl_len;
+			ioptr = (u32*)data->src;
+		}
+
+		status = 0;
+		for (block_count = 0;
+				block_count < data->blocks && !status;
+				block_count++) {
+			word_count = 0;
+			do {
+				status = mci_data_op(mci, ioptr, error_flags);
+				word_count++;
+				ioptr++;
+			} while (!status && word_count < (data->blocksize/4));
+#ifdef DEBUG
+			if (data->flags & MMC_DATA_READ)
+			{
+				printf("Read Data:\n");
+				print_buffer(0, data->dest, 1,
+					word_count*4, 0);
+			}
+#endif
+#ifdef DEBUG
+			if (!status && word_count < (sys_blocksize / 4))
+				printf("filling rest of block...\n");
+#endif
+			/* fill the rest of a full block */
+			while (!status && word_count < (sys_blocksize / 4)) {
+				status = mci_data_op(mci, &dummy,
+					error_flags);
+				word_count++;
+			}
+			if (status) {
+				dump_cmd(cmdr, cmd->cmdarg, status,
+					"Data Transfer Failed");
+				return COMM_ERR;
+			}
+		}
+
+		/* Wait for Transfer End */
+		i = 0;
+		do {
+			status = readl(&mci->sr);
+
+			if (status & error_flags) {
+				dump_cmd(cmdr, cmd->cmdarg, status,
+					"DTIP Wait Failed");
+				return COMM_ERR;
+			}
+			i++;
+		} while ((status & MMCI_BIT(DTIP)) && i < 10000);
+		if (status & MMCI_BIT(DTIP)) {
+			dump_cmd(cmdr, cmd->cmdarg, status,
+				"XFER DTIP never unset, ignoring");
+		}
+	}
+
+	return 0;
+}
+
+/* Entered into mmc structure during driver init */
+static void mci_set_ios(struct mmc *mmc)
+{
+	atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+	int bus_width = mmc->bus_width;
+	unsigned int version = atmel_mci_get_version(mci);
+	int busw;
+
+	/* Set the clock speed */
+	mci_set_mode(mmc, mmc->clock, MMC_DEFAULT_BLKLEN);
+
+	/*
+	 * set the bus width and select slot for this interface
+	 * there is no capability for multiple slots on the same interface yet
+	 */
+	if ((version & 0xf00) >= 0x300) {
+		switch (bus_width) {
+		case 8:
+			busw = 3;
+			break;
+		case 4:
+			busw = 2;
+			break;
+		default:
+			busw = 0;
+			break;
+		}
+
+		writel(busw << 6 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
+	} else {
+		busw = (bus_width == 4) ? 1 : 0;
+
+		writel(busw << 7 | MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);
+	}
+}
+
+/* Entered into mmc structure during driver init */
+static int mci_init(struct mmc *mmc)
+{
+	atmel_mci_t *mci = (atmel_mci_t *)mmc->priv;
+
+	/* Initialize controller */
+	writel(MMCI_BIT(SWRST), &mci->cr);	/* soft reset */
+	writel(MMCI_BIT(PWSDIS), &mci->cr);	/* disable power save */
+	writel(MMCI_BIT(MCIEN), &mci->cr);	/* enable mci */
+	writel(MMCI_BF(SCDSEL, MCI_BUS), &mci->sdcr);	/* select port */
+
+	/* This delay can be optimized, but stick with max value */
+	writel(0x7f, &mci->dtor);
+	/* Disable Interrupts */
+	writel(~0UL, &mci->idr);
+
+	/* Set default clocks and blocklen */
+	mci_set_mode(mmc, CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+
+	return 0;
+}
+
+/*
+ * This is the only exported function
+ *
+ * Call it with the MCI register base address
+ */
+int atmel_mci_init(void *regs)
+{
+	struct mmc *mmc = malloc(sizeof(struct mmc));
+	struct atmel_mci *mci;
+	unsigned int version;
+
+	if (!mmc)
+		return -1;
+
+	strcpy(mmc->name, "mci");
+	mmc->priv = regs;
+	mmc->send_cmd = mci_send_cmd;
+	mmc->set_ios = mci_set_ios;
+	mmc->init = mci_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+
+	/* need to be able to pass these in on a board by board basis */
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mci = (struct atmel_mci *)mmc->priv;
+	version = atmel_mci_get_version(mci);
+	if ((version & 0xf00) >= 0x300)
+		mmc->host_caps = MMC_MODE_8BIT;
+
+	mmc->host_caps |= MMC_MODE_4BIT;
+
+	/*
+	 * min and max frequencies determined by
+	 * max and min of clock divider
+	 */
+	mmc->f_min = get_mci_clk_rate() / (2*256);
+	mmc->f_max = get_mci_clk_rate() / (2*1);
+
+	mmc->b_max = 0;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/mmc.c b/marvell/uboot/drivers/mmc/mmc.c
new file mode 100644
index 0000000..c62b2a5
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mmc.c
@@ -0,0 +1,1526 @@
+/*
+ * Copyright 2008, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the Linux code
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <div64.h>
+#include "mmc_private.h"
+
+/* Set block count limit because of 16 bit register limit on some hardware*/
+#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
+#endif
+
+static struct list_head mmc_devices;
+static int cur_dev_num = -1;
+
+int __weak board_mmc_getwp(struct mmc *mmc)
+{
+	return -1;
+}
+
+int mmc_getwp(struct mmc *mmc)
+{
+	int wp;
+
+	wp = board_mmc_getwp(mmc);
+
+	if (wp < 0) {
+		if (mmc->getwp)
+			wp = mmc->getwp(mmc);
+		else
+			wp = 0;
+	}
+
+	return wp;
+}
+
+int __board_mmc_getcd(struct mmc *mmc) {
+	return -1;
+}
+
+int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
+	alias("__board_mmc_getcd")));
+
+int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	int ret;
+
+#ifdef CONFIG_MMC_TRACE
+	int i;
+	u8 *ptr;
+
+	printf("CMD_SEND:%d\n", cmd->cmdidx);
+	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
+	ret = mmc->send_cmd(mmc, cmd, data);
+	switch (cmd->resp_type) {
+		case MMC_RSP_NONE:
+			printf("\t\tMMC_RSP_NONE\n");
+			break;
+		case MMC_RSP_R1:
+			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
+				cmd->response[0]);
+			break;
+		case MMC_RSP_R1b:
+			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
+				cmd->response[0]);
+			break;
+		case MMC_RSP_R2:
+			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
+				cmd->response[0]);
+			printf("\t\t          \t\t 0x%08X \n",
+				cmd->response[1]);
+			printf("\t\t          \t\t 0x%08X \n",
+				cmd->response[2]);
+			printf("\t\t          \t\t 0x%08X \n",
+				cmd->response[3]);
+			printf("\n");
+			printf("\t\t\t\t\tDUMPING DATA\n");
+			for (i = 0; i < 4; i++) {
+				int j;
+				printf("\t\t\t\t\t%03d - ", i*4);
+				ptr = (u8 *)&cmd->response[i];
+				ptr += 3;
+				for (j = 0; j < 4; j++)
+					printf("%02X ", *ptr--);
+				printf("\n");
+			}
+			break;
+		case MMC_RSP_R3:
+			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
+				cmd->response[0]);
+			break;
+		default:
+			printf("\t\tERROR MMC rsp not supported\n");
+			break;
+	}
+#else
+	ret = mmc->send_cmd(mmc, cmd, data);
+#endif
+	return ret;
+}
+
+int mmc_send_status(struct mmc *mmc, int timeout)
+{
+	struct mmc_cmd cmd;
+	int err, retries = 5;
+#ifdef CONFIG_MMC_TRACE
+	int status;
+#endif
+
+	cmd.cmdidx = MMC_CMD_SEND_STATUS;
+	cmd.resp_type = MMC_RSP_R1;
+	if (!mmc_host_is_spi(mmc))
+		cmd.cmdarg = mmc->rca << 16;
+
+	do {
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+		if (!err) {
+			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
+			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
+			     MMC_STATE_PRG)
+				break;
+			else if (cmd.response[0] & MMC_STATUS_MASK) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+				printf("Status Error: 0x%08X\n",
+					cmd.response[0]);
+#endif
+				return COMM_ERR;
+			}
+		} else if (--retries < 0)
+			return err;
+
+		udelay(1000);
+
+	} while (timeout--);
+
+#ifdef CONFIG_MMC_TRACE
+	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
+	printf("CURR STATE:%d\n", status);
+#endif
+	if (timeout <= 0) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+		printf("Timeout waiting card ready\n");
+#endif
+		return TIMEOUT;
+	}
+
+	return 0;
+}
+
+int mmc_set_blocklen(struct mmc *mmc, int len)
+{
+	struct mmc_cmd cmd;
+
+	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = len;
+
+	udelay(1000);
+	return mmc_send_cmd(mmc, &cmd, NULL);
+}
+
+struct mmc *find_mmc_device(int dev_num)
+{
+	struct mmc *m;
+	struct list_head *entry;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+		if (m->block_dev.dev == dev_num)
+			return m;
+	}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+	printf("MMC Device %d not found\n", dev_num);
+#endif
+
+	return NULL;
+}
+
+static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
+			   lbaint_t blkcnt)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+
+	if (blkcnt > 1)
+		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+	else
+		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
+
+	if (mmc->high_capacity)
+		cmd.cmdarg = start;
+	else
+		cmd.cmdarg = start * mmc->read_bl_len;
+
+	cmd.resp_type = MMC_RSP_R1;
+
+	data.dest = dst;
+	data.blocks = blkcnt;
+	data.blocksize = mmc->read_bl_len;
+	data.flags = MMC_DATA_READ;
+
+	if (mmc_send_cmd(mmc, &cmd, &data))
+		return 0;
+
+	if (blkcnt > 1) {
+		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+		cmd.cmdarg = 0;
+		cmd.resp_type = MMC_RSP_R1b;
+		if (mmc_send_cmd(mmc, &cmd, NULL)) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+			printf("mmc fail to send stop cmd\n");
+#endif
+			return 0;
+		}
+	}
+
+	return blkcnt;
+}
+
+static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst)
+{
+	lbaint_t cur, blocks_todo = blkcnt;
+
+	if (blkcnt == 0)
+		return 0;
+
+	struct mmc *mmc = find_mmc_device(dev_num);
+	if (!mmc)
+		return 0;
+
+	if ((start + blkcnt) > mmc->block_dev.lba) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
+			start + blkcnt, mmc->block_dev.lba);
+#endif
+		return 0;
+	}
+
+	if (mmc_set_blocklen(mmc, mmc->read_bl_len))
+		return 0;
+
+	do {
+		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
+		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
+			return 0;
+		blocks_todo -= cur;
+		start += cur;
+		dst += cur * mmc->read_bl_len;
+	} while (blocks_todo > 0);
+
+	return blkcnt;
+}
+
+static int mmc_go_idle(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int err;
+
+	udelay(1000);
+
+	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
+	cmd.cmdarg = 0;
+	cmd.resp_type = MMC_RSP_NONE;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	udelay(2000);
+
+	return 0;
+}
+
+static int sd_send_op_cond(struct mmc *mmc)
+{
+	int timeout = 1000;
+	int err;
+	struct mmc_cmd cmd;
+
+	do {
+		cmd.cmdidx = MMC_CMD_APP_CMD;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = 0;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
+		cmd.resp_type = MMC_RSP_R3;
+
+		/*
+		 * Most cards do not answer if some reserved bits
+		 * in the ocr are set. However, Some controller
+		 * can set bit 7 (reserved for low voltages), but
+		 * how to manage low voltages SD card is not yet
+		 * specified.
+		 */
+		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
+			(mmc->voltages & 0xff8000);
+
+		if (mmc->version == SD_VERSION_2)
+			cmd.cmdarg |= OCR_HCS;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		udelay(1000);
+	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
+
+	if (timeout <= 0)
+		return UNUSABLE_ERR;
+
+	if (mmc->version != SD_VERSION_2)
+		mmc->version = SD_VERSION_1_0;
+
+	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+		cmd.resp_type = MMC_RSP_R3;
+		cmd.cmdarg = 0;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+	}
+
+	mmc->ocr = cmd.response[0];
+
+	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+	mmc->rca = 0;
+
+	return 0;
+}
+
+/* We pass in the cmd since otherwise the init seems to fail */
+static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
+		int use_arg)
+{
+	int err;
+
+	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
+	cmd->resp_type = MMC_RSP_R3;
+	cmd->cmdarg = 0;
+	if (use_arg && !mmc_host_is_spi(mmc)) {
+		cmd->cmdarg =
+			(mmc->voltages &
+			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
+			(mmc->op_cond_response & OCR_ACCESS_MODE);
+
+		if (mmc->host_caps & MMC_MODE_HC)
+			cmd->cmdarg |= OCR_HCS;
+	}
+	err = mmc_send_cmd(mmc, cmd, NULL);
+	if (err)
+		return err;
+	mmc->op_cond_response = cmd->response[0];
+	return 0;
+}
+
+int mmc_send_op_cond(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int err, i;
+
+	/* Some cards seem to need this */
+	mmc_go_idle(mmc);
+
+ 	/* Asking to the card its capabilities */
+	mmc->op_cond_pending = 1;
+	for (i = 0; i < 2; i++) {
+		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
+		if (err)
+			return err;
+
+		/* exit if not busy (flag seems to be inverted) */
+		if (mmc->op_cond_response & OCR_BUSY)
+			return 0;
+	}
+	return IN_PROGRESS;
+}
+
+int mmc_complete_op_cond(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int timeout = 1000;
+	uint start;
+	int err;
+
+	mmc->op_cond_pending = 0;
+	start = get_timer(0);
+	do {
+		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
+		if (err)
+			return err;
+		if (get_timer(start) > timeout)
+			return UNUSABLE_ERR;
+		udelay(100);
+	} while (!(mmc->op_cond_response & OCR_BUSY));
+
+	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
+		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
+		cmd.resp_type = MMC_RSP_R3;
+		cmd.cmdarg = 0;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+	}
+
+	mmc->version = MMC_VERSION_UNKNOWN;
+	mmc->ocr = cmd.response[0];
+
+	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+	mmc->rca = 0;
+
+	return 0;
+}
+
+
+static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	int err;
+
+	/* Get the Card Status Register */
+	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = 0;
+
+	data.dest = (char *)ext_csd;
+	data.blocks = 1;
+	data.blocksize = MMC_MAX_BLOCK_LEN;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	return err;
+}
+
+
+static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+{
+	struct mmc_cmd cmd;
+	int timeout = 1000;
+	int ret;
+
+	cmd.cmdidx = MMC_CMD_SWITCH;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+				 (index << 16) |
+				 (value << 8);
+
+	ret = mmc_send_cmd(mmc, &cmd, NULL);
+
+	/* Waiting for the ready status */
+	if (!ret)
+		ret = mmc_send_status(mmc, timeout);
+
+	return ret;
+
+}
+
+static int mmc_change_freq(struct mmc *mmc)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+	char cardtype;
+	int err;
+
+	mmc->card_caps = 0;
+
+	if (mmc_host_is_spi(mmc))
+		return 0;
+
+	/* Only version 4 supports high-speed */
+	if (mmc->version < MMC_VERSION_4)
+		return 0;
+
+	err = mmc_send_ext_csd(mmc, ext_csd);
+
+	if (err)
+		return err;
+
+	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
+
+	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
+
+	if (err)
+		return err;
+
+	/* Now check to see that it worked */
+	err = mmc_send_ext_csd(mmc, ext_csd);
+
+	if (err)
+		return err;
+
+	/* No high-speed support */
+	if (!ext_csd[EXT_CSD_HS_TIMING])
+		return 0;
+
+	/* High Speed is set, there are two types: 52MHz and 26MHz */
+	if (cardtype & MMC_HS_52MHZ)
+		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+	else
+		mmc->card_caps |= MMC_MODE_HS;
+
+	return 0;
+}
+
+static int mmc_set_capacity(struct mmc *mmc, int part_num)
+{
+	switch (part_num) {
+	case 0:
+		mmc->capacity = mmc->capacity_user;
+		break;
+	case 1:
+	case 2:
+		mmc->capacity = mmc->capacity_boot;
+		break;
+	case 3:
+		mmc->capacity = mmc->capacity_rpmb;
+		break;
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		mmc->capacity = mmc->capacity_gp[part_num - 4];
+		break;
+	default:
+		return -1;
+	}
+
+	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+
+	return 0;
+}
+
+int mmc_switch_part(int dev_num, unsigned int part_num)
+{
+	struct mmc *mmc = find_mmc_device(dev_num);
+	int ret;
+
+	if (!mmc)
+		return -1;
+
+	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
+			 (mmc->part_config & ~PART_ACCESS_MASK)
+			 | (part_num & PART_ACCESS_MASK));
+	if (ret)
+		return ret;
+
+	return mmc_set_capacity(mmc, part_num);
+}
+
+int mmc_getcd(struct mmc *mmc)
+{
+	int cd;
+
+	cd = board_mmc_getcd(mmc);
+
+	if (cd < 0) {
+		if (mmc->getcd)
+			cd = mmc->getcd(mmc);
+		else
+			cd = 1;
+	}
+
+	return cd;
+}
+
+static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+
+	/* Switch the frequency */
+	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = (mode << 31) | 0xffffff;
+	cmd.cmdarg &= ~(0xf << (group * 4));
+	cmd.cmdarg |= value << (group * 4);
+
+	data.dest = (char *)resp;
+	data.blocksize = 64;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+
+	return mmc_send_cmd(mmc, &cmd, &data);
+}
+
+
+static int sd_change_freq(struct mmc *mmc)
+{
+	int err;
+	struct mmc_cmd cmd;
+	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
+	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
+	struct mmc_data data;
+	int timeout;
+
+	mmc->card_caps = 0;
+
+	if (mmc_host_is_spi(mmc))
+		return 0;
+
+	/* Read the SCR to find out if this card supports higher speeds */
+	cmd.cmdidx = MMC_CMD_APP_CMD;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = mmc->rca << 16;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = 0;
+
+	timeout = 3;
+
+retry_scr:
+	data.dest = (char *)scr;
+	data.blocksize = 8;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+
+	err = mmc_send_cmd(mmc, &cmd, &data);
+
+	if (err) {
+		if (timeout--)
+			goto retry_scr;
+
+		return err;
+	}
+
+	mmc->scr[0] = __be32_to_cpu(scr[0]);
+	mmc->scr[1] = __be32_to_cpu(scr[1]);
+
+	switch ((mmc->scr[0] >> 24) & 0xf) {
+		case 0:
+			mmc->version = SD_VERSION_1_0;
+			break;
+		case 1:
+			mmc->version = SD_VERSION_1_10;
+			break;
+		case 2:
+			mmc->version = SD_VERSION_2;
+			if ((mmc->scr[0] >> 15) & 0x1)
+				mmc->version = SD_VERSION_3;
+			break;
+		default:
+			mmc->version = SD_VERSION_1_0;
+			break;
+	}
+
+	if (mmc->scr[0] & SD_DATA_4BIT)
+		mmc->card_caps |= MMC_MODE_4BIT;
+
+	/* Version 1.0 doesn't support switching */
+	if (mmc->version == SD_VERSION_1_0)
+		return 0;
+
+	timeout = 4;
+	while (timeout--) {
+		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
+				(u8 *)switch_status);
+
+		if (err)
+			return err;
+
+		/* The high-speed function is busy.  Try again */
+		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
+			break;
+	}
+
+	/* If high-speed isn't supported, we return */
+	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
+		return 0;
+
+	/*
+	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
+	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
+	 * This can avoid furthur problem when the card runs in different
+	 * mode between the host.
+	 */
+	if (!((mmc->host_caps & MMC_MODE_HS_52MHz) &&
+		(mmc->host_caps & MMC_MODE_HS)))
+		return 0;
+
+	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
+
+	if (err)
+		return err;
+
+	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
+		mmc->card_caps |= MMC_MODE_HS;
+
+	return 0;
+}
+
+/* frequency bases */
+/* divided by 10 to be nice to platforms without floating point */
+static const int fbase[] = {
+	10000,
+	100000,
+	1000000,
+	10000000,
+};
+
+/* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
+ * to platforms without floating point.
+ */
+static const int multipliers[] = {
+	0,	/* reserved */
+	10,
+	12,
+	13,
+	15,
+	20,
+	25,
+	30,
+	35,
+	40,
+	45,
+	50,
+	55,
+	60,
+	70,
+	80,
+};
+
+static void mmc_set_ios(struct mmc *mmc)
+{
+	mmc->set_ios(mmc);
+}
+
+static void mmc_set_74_clk(struct mmc *mmc)
+{
+	mmc->set_74_clk(mmc);
+}
+
+void mmc_set_clock(struct mmc *mmc, uint clock)
+{
+	if (clock > mmc->f_max)
+		clock = mmc->f_max;
+
+	if (clock < mmc->f_min)
+		clock = mmc->f_min;
+
+	mmc->clock = clock;
+
+	mmc_set_ios(mmc);
+}
+
+static void mmc_set_bus_width(struct mmc *mmc, uint width)
+{
+	mmc->bus_width = width;
+
+	mmc_set_ios(mmc);
+}
+
+static int mmc_startup(struct mmc *mmc)
+{
+	int err, i;
+	uint mult, freq;
+	u64 cmult, csize, capacity;
+	struct mmc_cmd cmd;
+	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
+	int timeout = 1000;
+
+#ifdef CONFIG_MMC_SPI_CRC_ON
+	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
+		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = 1;
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+	}
+#endif
+
+	/* Put the Card in Identify Mode */
+	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
+		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
+	cmd.resp_type = MMC_RSP_R2;
+	cmd.cmdarg = 0;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	memcpy(mmc->cid, cmd.response, 16);
+
+	/*
+	 * For MMC cards, set the Relative Address.
+	 * For SD cards, get the Relatvie Address.
+	 * This also puts the cards into Standby State
+	 */
+	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+		cmd.cmdarg = mmc->rca << 16;
+		cmd.resp_type = MMC_RSP_R6;
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+
+		if (IS_SD(mmc))
+			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+	}
+
+	/* Get the Card-Specific Data */
+	cmd.cmdidx = MMC_CMD_SEND_CSD;
+	cmd.resp_type = MMC_RSP_R2;
+	cmd.cmdarg = mmc->rca << 16;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	/* Waiting for the ready status */
+	mmc_send_status(mmc, timeout);
+
+	if (err)
+		return err;
+
+	mmc->csd[0] = cmd.response[0];
+	mmc->csd[1] = cmd.response[1];
+	mmc->csd[2] = cmd.response[2];
+	mmc->csd[3] = cmd.response[3];
+
+	if (mmc->version == MMC_VERSION_UNKNOWN) {
+		int version = (cmd.response[0] >> 26) & 0xf;
+
+		switch (version) {
+			case 0:
+				mmc->version = MMC_VERSION_1_2;
+				break;
+			case 1:
+				mmc->version = MMC_VERSION_1_4;
+				break;
+			case 2:
+				mmc->version = MMC_VERSION_2_2;
+				break;
+			case 3:
+				mmc->version = MMC_VERSION_3;
+				break;
+			case 4:
+				mmc->version = MMC_VERSION_4;
+				break;
+			default:
+				mmc->version = MMC_VERSION_1_2;
+				break;
+		}
+	}
+
+	/* divide frequency by 10, since the mults are 10x bigger */
+	freq = fbase[(cmd.response[0] & 0x7)];
+	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
+
+	mmc->tran_speed = freq * mult;
+
+	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
+	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
+
+	if (IS_SD(mmc))
+		mmc->write_bl_len = mmc->read_bl_len;
+	else
+		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
+
+	if (mmc->high_capacity) {
+		csize = (mmc->csd[1] & 0x3f) << 16
+			| (mmc->csd[2] & 0xffff0000) >> 16;
+		cmult = 8;
+	} else {
+		csize = (mmc->csd[1] & 0x3ff) << 2
+			| (mmc->csd[2] & 0xc0000000) >> 30;
+		cmult = (mmc->csd[2] & 0x00038000) >> 15;
+	}
+
+	mmc->capacity_user = (csize + 1) << (cmult + 2);
+	mmc->capacity_user *= mmc->read_bl_len;
+	mmc->capacity_boot = 0;
+	mmc->capacity_rpmb = 0;
+	for (i = 0; i < 4; i++)
+		mmc->capacity_gp[i] = 0;
+
+	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
+		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+
+	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
+		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+
+	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
+		cmd.cmdidx = MMC_CMD_SET_DSR;
+		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
+		cmd.resp_type = MMC_RSP_NONE;
+		if (mmc_send_cmd(mmc, &cmd, NULL))
+			printf("MMC: SET_DSR failed\n");
+	}
+
+	/* Select the card, and put it into Transfer Mode */
+	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+		cmd.cmdidx = MMC_CMD_SELECT_CARD;
+		cmd.resp_type = MMC_RSP_R1;
+		cmd.cmdarg = mmc->rca << 16;
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+
+		if (err)
+			return err;
+	}
+
+	/*
+	 * For SD, its erase group is always one sector
+	 */
+	mmc->erase_grp_size = 1;
+	mmc->part_config = MMCPART_NOAVAILABLE;
+	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)) {
+			/*
+			 * According to the JEDEC Standard, the value of
+			 * ext_csd's capacity is valid if the value is more
+			 * than 2GB
+			 */
+			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
+					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
+					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
+					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+			capacity *= MMC_MAX_BLOCK_LEN;
+			if ((capacity >> 20) > 2 * 1024)
+				mmc->capacity_user = capacity;
+		}
+
+		switch (ext_csd[EXT_CSD_REV]) {
+		case 1:
+			mmc->version = MMC_VERSION_4_1;
+			break;
+		case 2:
+			mmc->version = MMC_VERSION_4_2;
+			break;
+		case 3:
+			mmc->version = MMC_VERSION_4_3;
+			break;
+		case 5:
+			mmc->version = MMC_VERSION_4_41;
+			break;
+		case 6:
+			mmc->version = MMC_VERSION_4_5;
+			break;
+		}
+
+		/*
+		 * Host needs to enable ERASE_GRP_DEF bit if device is
+		 * partitioned. This bit will be lost every time after a reset
+		 * or power off. This will affect erase size.
+		 */
+		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
+		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) {
+			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+				EXT_CSD_ERASE_GROUP_DEF, 1);
+
+			if (err)
+				return err;
+
+			/* Read out group size from ext_csd */
+			mmc->erase_grp_size =
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] *
+					MMC_MAX_BLOCK_LEN * 1024;
+		} else {
+			/* Calculate the group size from the csd value. */
+			int erase_gsz, erase_gmul;
+			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
+			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
+			mmc->erase_grp_size = (erase_gsz + 1)
+				* (erase_gmul + 1);
+		}
+
+		/* store the partition info of emmc */
+		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+		    ext_csd[EXT_CSD_BOOT_MULT])
+			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+
+		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+		for (i = 0; i < 4; i++) {
+			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
+				(ext_csd[idx + 1] << 8) + ext_csd[idx];
+			mmc->capacity_gp[i] *=
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+		}
+	}
+
+	err = mmc_set_capacity(mmc, mmc->part_num);
+	if (err)
+		return err;
+
+	if (IS_SD(mmc))
+		err = sd_change_freq(mmc);
+	else
+		err = mmc_change_freq(mmc);
+
+	if (err)
+		return err;
+
+	/* Restrict card's capabilities by what the host can do */
+	mmc->card_caps &= mmc->host_caps;
+
+	if (IS_SD(mmc)) {
+		if (mmc->card_caps & MMC_MODE_4BIT) {
+			cmd.cmdidx = MMC_CMD_APP_CMD;
+			cmd.resp_type = MMC_RSP_R1;
+			cmd.cmdarg = mmc->rca << 16;
+
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+			if (err)
+				return err;
+
+			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
+			cmd.resp_type = MMC_RSP_R1;
+			cmd.cmdarg = 2;
+			err = mmc_send_cmd(mmc, &cmd, NULL);
+			if (err)
+				return err;
+
+			mmc_set_bus_width(mmc, 4);
+		}
+
+		if (mmc->card_caps & MMC_MODE_HS)
+			mmc->tran_speed = 50000000;
+		else
+			mmc->tran_speed = 25000000;
+	} else {
+		int idx;
+
+		/* An array of possible bus widths in order of preference */
+		static unsigned ext_csd_bits[] = {
+			EXT_CSD_BUS_WIDTH_8,
+			EXT_CSD_BUS_WIDTH_4,
+			EXT_CSD_BUS_WIDTH_1,
+		};
+
+		/* An array to map CSD bus widths to host cap bits */
+		static unsigned ext_to_hostcaps[] = {
+			[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
+			[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
+		};
+
+		/* An array to map chosen bus width to an integer */
+		static unsigned widths[] = {
+			8, 4, 1,
+		};
+
+		for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
+			unsigned int extw = ext_csd_bits[idx];
+
+			/*
+			 * Check to make sure the controller supports
+			 * this bus width, if it's more than 1
+			 */
+			if (extw != EXT_CSD_BUS_WIDTH_1 &&
+					!(mmc->host_caps & ext_to_hostcaps[extw]))
+				continue;
+
+			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_BUS_WIDTH, extw);
+
+			if (err)
+				continue;
+
+			mmc_set_bus_width(mmc, widths[idx]);
+
+			err = mmc_send_ext_csd(mmc, test_csd);
+			if (!err && ext_csd[EXT_CSD_PARTITIONING_SUPPORT] \
+				    == test_csd[EXT_CSD_PARTITIONING_SUPPORT]
+				 && ext_csd[EXT_CSD_ERASE_GROUP_DEF] \
+				    == test_csd[EXT_CSD_ERASE_GROUP_DEF] \
+				 && ext_csd[EXT_CSD_REV] \
+				    == test_csd[EXT_CSD_REV]
+				 && ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] \
+				    == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+				 && memcmp(&ext_csd[EXT_CSD_SEC_CNT], \
+					&test_csd[EXT_CSD_SEC_CNT], 4) == 0) {
+
+				mmc->card_caps |= ext_to_hostcaps[extw];
+				break;
+			}
+		}
+
+		if (mmc->card_caps & MMC_MODE_HS) {
+			if (mmc->card_caps & MMC_MODE_HS_52MHz)
+				mmc->tran_speed = 52000000;
+			else
+				mmc->tran_speed = 26000000;
+		}
+	}
+
+	mmc_set_clock(mmc, mmc->tran_speed);
+
+	/* fill in device description */
+	mmc->block_dev.lun = 0;
+	mmc->block_dev.type = 0;
+	mmc->block_dev.blksz = mmc->read_bl_len;
+	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
+	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
+		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
+		(mmc->cid[3] >> 16) & 0xffff);
+	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
+		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
+		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
+		(mmc->cid[2] >> 24) & 0xff);
+	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
+		(mmc->cid[2] >> 16) & 0xf);
+#else
+	mmc->block_dev.vendor[0] = 0;
+	mmc->block_dev.product[0] = 0;
+	mmc->block_dev.revision[0] = 0;
+#endif
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
+	init_part(&mmc->block_dev);
+#endif
+
+	return 0;
+}
+
+static int mmc_send_if_cond(struct mmc *mmc)
+{
+	struct mmc_cmd cmd;
+	int err;
+
+	cmd.cmdidx = SD_CMD_SEND_IF_COND;
+	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
+	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
+	cmd.resp_type = MMC_RSP_R7;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+
+	if (err)
+		return err;
+
+	if ((cmd.response[0] & 0xff) != 0xaa)
+		return UNUSABLE_ERR;
+	else
+		mmc->version = SD_VERSION_2;
+
+	return 0;
+}
+
+static int mmc_dev_init(int dev_num);
+int mmc_register(struct mmc *mmc)
+{
+	/* Setup dsr related values */
+	mmc->dsr_imp = 0;
+	mmc->dsr = 0xffffffff;
+	/* Setup the universal parts of the block interface just once */
+	mmc->block_dev.if_type = IF_TYPE_MMC;
+	mmc->block_dev.dev = cur_dev_num++;
+	mmc->block_dev.removable = 1;
+	mmc->block_dev.block_read = mmc_bread;
+	mmc->block_dev.block_write = mmc_bwrite;
+	mmc->block_dev.block_erase = mmc_berase;
+	mmc->block_dev.dev_init = mmc_dev_init;
+	if (!mmc->b_max)
+		mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+	INIT_LIST_HEAD (&mmc->link);
+
+	list_add_tail (&mmc->link, &mmc_devices);
+
+	return 0;
+}
+
+#ifdef CONFIG_PARTITIONS
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+	struct mmc *mmc = find_mmc_device(dev);
+	if (!mmc || mmc_init(mmc))
+		return NULL;
+
+	return &mmc->block_dev;
+}
+#endif
+
+int mmc_start_init(struct mmc *mmc)
+{
+	int err;
+
+	if (mmc_getcd(mmc) == 0) {
+		mmc->has_init = 0;
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+		printf("MMC: no card present\n");
+#endif
+		return NO_CARD_ERR;
+	}
+
+	if (mmc->has_init)
+		return 0;
+
+	err = mmc->init(mmc);
+
+	if (err)
+		return err;
+
+	mmc_set_bus_width(mmc, 1);
+	mmc_set_clock(mmc, 1);
+	mmc_set_74_clk(mmc);
+
+	/* Reset the Card */
+	err = mmc_go_idle(mmc);
+
+	if (err)
+		return err;
+
+	/* The internal partition reset to user partition(0) at every CMD0*/
+	mmc->part_num = 0;
+
+	/* Test for SD version 2 */
+	err = mmc_send_if_cond(mmc);
+
+	/* Now try to get the SD card's operating condition */
+	err = sd_send_op_cond(mmc);
+
+	/* If the command timed out, we check for an MMC card */
+	if (err == TIMEOUT) {
+		err = mmc_send_op_cond(mmc);
+
+		if (err && err != IN_PROGRESS) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+			printf("Card did not respond to voltage select!\n");
+#endif
+			return UNUSABLE_ERR;
+		}
+	}
+
+	if (err == IN_PROGRESS)
+		mmc->init_in_progress = 1;
+
+	return err;
+}
+
+static int mmc_complete_init(struct mmc *mmc)
+{
+	int err = 0;
+
+	if (mmc->op_cond_pending)
+		err = mmc_complete_op_cond(mmc);
+
+	if (!err)
+		err = mmc_startup(mmc);
+	if (err)
+		mmc->has_init = 0;
+	else
+		mmc->has_init = 1;
+	mmc->init_in_progress = 0;
+	return err;
+}
+
+int mmc_init(struct mmc *mmc)
+{
+	int err = IN_PROGRESS;
+	unsigned start = get_timer(0);
+
+	if (mmc->has_init)
+		return 0;
+	if (!mmc->init_in_progress)
+		err = mmc_start_init(mmc);
+
+	if (!err || err == IN_PROGRESS)
+		err = mmc_complete_init(mmc);
+	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
+	return err;
+}
+
+int mmc_set_dsr(struct mmc *mmc, u16 val)
+{
+	mmc->dsr = val;
+	return 0;
+}
+
+static int mmc_dev_init(int dev_num)
+{
+	struct mmc *mmc = find_mmc_device(dev_num);
+	if (!mmc)
+		return -1;
+
+	return mmc_init(mmc);
+}
+
+/*
+ * CPU and board-specific MMC initializations.  Aliased function
+ * signals caller to move on
+ */
+static int __def_mmc_init(bd_t *bis)
+{
+	return -1;
+}
+
+int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
+int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+
+void print_mmc_devices(char separator)
+{
+	struct mmc *m;
+	struct list_head *entry;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+		printf("%s: %d", m->name, m->block_dev.dev);
+
+		if (entry->next != &mmc_devices)
+			printf("%c ", separator);
+	}
+
+	printf("\n");
+}
+
+#else
+void print_mmc_devices(char separator) { }
+#endif
+
+int get_mmc_num(void)
+{
+	return cur_dev_num;
+}
+
+void mmc_set_preinit(struct mmc *mmc, int preinit)
+{
+	mmc->preinit = preinit;
+}
+
+static void do_preinit(void)
+{
+	struct mmc *m;
+	struct list_head *entry;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+		if (m->preinit)
+			mmc_start_init(m);
+	}
+}
+
+
+int mmc_initialize(bd_t *bis)
+{
+	INIT_LIST_HEAD (&mmc_devices);
+	cur_dev_num = 0;
+
+	if (board_mmc_init(bis) < 0)
+		cpu_mmc_init(bis);
+
+#ifndef CONFIG_SPL_BUILD
+	print_mmc_devices(',');
+#endif
+
+	do_preinit();
+	return 0;
+}
+
+#ifdef CONFIG_SUPPORT_EMMC_BOOT
+/*
+ * This function changes the size of boot partition and the size of rpmb
+ * partition present on EMMC devices.
+ *
+ * Input Parameters:
+ * struct *mmc: pointer for the mmc device strcuture
+ * bootsize: size of boot partition
+ * rpmbsize: size of rpmb partition
+ *
+ * Returns 0 on success.
+ */
+
+int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
+				unsigned long rpmbsize)
+{
+	int err;
+	struct mmc_cmd cmd;
+
+	/* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
+	cmd.cmdidx = MMC_CMD_RES_MAN;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = MMC_CMD62_ARG1;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err) {
+		debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
+		return err;
+	}
+
+	/* Boot partition changing mode */
+	cmd.cmdidx = MMC_CMD_RES_MAN;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = MMC_CMD62_ARG2;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err) {
+		debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
+		return err;
+	}
+	/* boot partition size is multiple of 128KB */
+	bootsize = (bootsize * 1024) / 128;
+
+	/* Arg: boot partition size */
+	cmd.cmdidx = MMC_CMD_RES_MAN;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = bootsize;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err) {
+		debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
+		return err;
+	}
+	/* RPMB partition size is multiple of 128KB */
+	rpmbsize = (rpmbsize * 1024) / 128;
+	/* Arg: RPMB partition size */
+	cmd.cmdidx = MMC_CMD_RES_MAN;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = rpmbsize;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err) {
+		debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
+		return err;
+	}
+	return 0;
+}
+
+/*
+ * This function shall form and send the commands to open / close the
+ * boot partition specified by user.
+ *
+ * Input Parameters:
+ * ack: 0x0 - No boot acknowledge sent (default)
+ *	0x1 - Boot acknowledge sent during boot operation
+ * part_num: User selects boot data that will be sent to master
+ *	0x0 - Device not boot enabled (default)
+ *	0x1 - Boot partition 1 enabled for boot
+ *	0x2 - Boot partition 2 enabled for boot
+ * access: User selects partitions to access
+ *	0x0 : No access to boot partition (default)
+ *	0x1 : R/W boot partition 1
+ *	0x2 : R/W boot partition 2
+ *	0x3 : R/W Replay Protected Memory Block (RPMB)
+ *
+ * Returns 0 on success.
+ */
+int mmc_boot_part_access(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
+{
+	int err;
+	struct mmc_cmd cmd;
+
+	/* Boot ack enable, boot partition enable , boot partition access */
+	cmd.cmdidx = MMC_CMD_SWITCH;
+	cmd.resp_type = MMC_RSP_R1b;
+
+	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+			(EXT_CSD_PART_CONF << 16) |
+			((EXT_CSD_BOOT_ACK(ack) |
+			EXT_CSD_BOOT_PART_NUM(part_num) |
+			EXT_CSD_PARTITION_ACCESS(access)) << 8);
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err) {
+		if (access) {
+			debug("mmc boot partition#%d open fail:Error1 = %d\n",
+			      part_num, err);
+		} else {
+			debug("mmc boot partition#%d close fail:Error = %d\n",
+			      part_num, err);
+		}
+		return err;
+	}
+
+	if (access) {
+		/* 4bit transfer mode at booting time. */
+		cmd.cmdidx = MMC_CMD_SWITCH;
+		cmd.resp_type = MMC_RSP_R1b;
+
+		cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+				(EXT_CSD_BOOT_BUS_WIDTH << 16) |
+				((1 << 0) << 8);
+
+		err = mmc_send_cmd(mmc, &cmd, NULL);
+		if (err) {
+			debug("mmc boot partition#%d open fail:Error2 = %d\n",
+			      part_num, err);
+			return err;
+		}
+	}
+	return 0;
+}
+#endif
diff --git a/marvell/uboot/drivers/mmc/mmc_private.h b/marvell/uboot/drivers/mmc/mmc_private.h
new file mode 100644
index 0000000..16dcf9f
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mmc_private.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008,2010 Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based (loosely) on the Linux code
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _MMC_PRIVATE_H_
+#define _MMC_PRIVATE_H_
+
+#include <mmc.h>
+
+extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data);
+extern int mmc_send_status(struct mmc *mmc, int timeout);
+extern int mmc_set_blocklen(struct mmc *mmc, int len);
+
+#ifndef CONFIG_SPL_BUILD
+
+extern unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt);
+
+extern ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
+		const void *src);
+
+#else /* CONFIG_SPL_BUILD */
+
+/* SPL will never write or erase, declare dummies to reduce code size. */
+
+static inline unsigned long mmc_berase(int dev_num, lbaint_t start,
+		lbaint_t blkcnt)
+{
+	return 0;
+}
+
+static inline ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt,
+		const void *src)
+{
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
+
+#endif /* _MMC_PRIVATE_H_ */
diff --git a/marvell/uboot/drivers/mmc/mmc_spi.c b/marvell/uboot/drivers/mmc/mmc_spi.c
new file mode 100644
index 0000000..fe6a5a1
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mmc_spi.c
@@ -0,0 +1,287 @@
+/*
+ * generic mmc spi driver
+ *
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Licensed under the GPL-2 or later.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+#include <spi.h>
+#include <crc.h>
+#include <linux/crc7.h>
+#include <linux/byteorder/swab.h>
+
+/* MMC/SD in SPI mode reports R1 status always */
+#define R1_SPI_IDLE		(1 << 0)
+#define R1_SPI_ERASE_RESET	(1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND	(1 << 2)
+#define R1_SPI_COM_CRC		(1 << 3)
+#define R1_SPI_ERASE_SEQ	(1 << 4)
+#define R1_SPI_ADDRESS		(1 << 5)
+#define R1_SPI_PARAMETER	(1 << 6)
+/* R1 bit 7 is always zero, reuse this bit for error */
+#define R1_SPI_ERROR		(1 << 7)
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED		((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR		((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR		((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
+#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
+
+/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
+#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
+
+/* bus capability */
+#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
+#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
+
+/* timeout value */
+#define CTOUT 8
+#define RTOUT 3000000 /* 1 sec */
+#define WTOUT 3000000 /* 1 sec */
+
+static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
+{
+	struct spi_slave *spi = mmc->priv;
+	u8 cmdo[7];
+	u8 r1;
+	int i;
+	cmdo[0] = 0xff;
+	cmdo[1] = MMC_SPI_CMD(cmdidx);
+	cmdo[2] = cmdarg >> 24;
+	cmdo[3] = cmdarg >> 16;
+	cmdo[4] = cmdarg >> 8;
+	cmdo[5] = cmdarg;
+	cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
+	spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
+	for (i = 0; i < CTOUT; i++) {
+		spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+		if (i && (r1 & 0x80) == 0) /* r1 response */
+			break;
+	}
+	debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
+	return r1;
+}
+
+static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
+				u32 bcnt, u32 bsize)
+{
+	struct spi_slave *spi = mmc->priv;
+	u8 *buf = xbuf;
+	u8 r1;
+	u16 crc;
+	int i;
+	while (bcnt--) {
+		for (i = 0; i < RTOUT; i++) {
+			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+			if (r1 != 0xff) /* data token */
+				break;
+		}
+		debug("%s:tok%d %x\n", __func__, i, r1);
+		if (r1 == SPI_TOKEN_SINGLE) {
+			spi_xfer(spi, bsize * 8, NULL, buf, 0);
+			spi_xfer(spi, 2 * 8, NULL, &crc, 0);
+#ifdef CONFIG_MMC_SPI_CRC_ON
+			if (swab16(cyg_crc16(buf, bsize)) != crc) {
+				debug("%s: CRC error\n", mmc->name);
+				r1 = R1_SPI_COM_CRC;
+				break;
+			}
+#endif
+			r1 = 0;
+		} else {
+			r1 = R1_SPI_ERROR;
+			break;
+		}
+		buf += bsize;
+	}
+	return r1;
+}
+
+static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
+			      u32 bcnt, u32 bsize, int multi)
+{
+	struct spi_slave *spi = mmc->priv;
+	const u8 *buf = xbuf;
+	u8 r1;
+	u16 crc;
+	u8 tok[2];
+	int i;
+	tok[0] = 0xff;
+	tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
+	while (bcnt--) {
+#ifdef CONFIG_MMC_SPI_CRC_ON
+		crc = swab16(cyg_crc16((u8 *)buf, bsize));
+#endif
+		spi_xfer(spi, 2 * 8, tok, NULL, 0);
+		spi_xfer(spi, bsize * 8, buf, NULL, 0);
+		spi_xfer(spi, 2 * 8, &crc, NULL, 0);
+		for (i = 0; i < CTOUT; i++) {
+			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+			if ((r1 & 0x10) == 0) /* response token */
+				break;
+		}
+		debug("%s:tok%d %x\n", __func__, i, r1);
+		if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
+			for (i = 0; i < WTOUT; i++) { /* wait busy */
+				spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+				if (i && r1 == 0xff) {
+					r1 = 0;
+					break;
+				}
+			}
+			if (i == WTOUT) {
+				debug("%s:wtout %x\n", __func__, r1);
+				r1 = R1_SPI_ERROR;
+				break;
+			}
+		} else {
+			debug("%s: err %x\n", __func__, r1);
+			r1 = R1_SPI_COM_CRC;
+			break;
+		}
+		buf += bsize;
+	}
+	if (multi && bcnt == -1) { /* stop multi write */
+		tok[1] = SPI_TOKEN_STOP_TRAN;
+		spi_xfer(spi, 2 * 8, tok, NULL, 0);
+		for (i = 0; i < WTOUT; i++) { /* wait busy */
+			spi_xfer(spi, 1 * 8, NULL, &r1, 0);
+			if (i && r1 == 0xff) {
+				r1 = 0;
+				break;
+			}
+		}
+		if (i == WTOUT) {
+			debug("%s:wstop %x\n", __func__, r1);
+			r1 = R1_SPI_ERROR;
+		}
+	}
+	return r1;
+}
+
+static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
+		struct mmc_data *data)
+{
+	struct spi_slave *spi = mmc->priv;
+	u8 r1;
+	int i;
+	int ret = 0;
+	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);
+	if (r1 == 0xff) { /* no response */
+		ret = NO_CARD_ERR;
+		goto done;
+	} else if (r1 & R1_SPI_COM_CRC) {
+		ret = COMM_ERR;
+		goto done;
+	} else if (r1 & ~R1_SPI_IDLE) { /* other errors */
+		ret = TIMEOUT;
+		goto done;
+	} else if (cmd->resp_type == MMC_RSP_R2) {
+		r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
+		for (i = 0; i < 4; i++)
+			cmd->response[i] = swab32(cmd->response[i]);
+		debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1],
+		      cmd->response[2], cmd->response[3]);
+	} else if (!data) {
+		switch (cmd->cmdidx) {
+		case SD_CMD_APP_SEND_OP_COND:
+		case MMC_CMD_SEND_OP_COND:
+			cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
+			break;
+		case SD_CMD_SEND_IF_COND:
+		case MMC_CMD_SPI_READ_OCR:
+			spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
+			cmd->response[0] = swab32(cmd->response[0]);
+			debug("r32 %x\n", cmd->response[0]);
+			break;
+		case MMC_CMD_SEND_STATUS:
+			spi_xfer(spi, 1 * 8, NULL, cmd->response, 0);
+			cmd->response[0] = (cmd->response[0] & 0xff) ?
+				MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
+			break;
+		}
+	} else {
+		debug("%s:data %x %x %x\n", __func__,
+		      data->flags, data->blocks, data->blocksize);
+		if (data->flags == MMC_DATA_READ)
+			r1 = mmc_spi_readdata(mmc, data->dest,
+				data->blocks, data->blocksize);
+		else if  (data->flags == MMC_DATA_WRITE)
+			r1 = mmc_spi_writedata(mmc, data->src,
+				data->blocks, data->blocksize,
+				(cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK));
+		if (r1 & R1_SPI_COM_CRC)
+			ret = COMM_ERR;
+		else if (r1) /* other errors */
+			ret = TIMEOUT;
+	}
+done:
+	spi_cs_deactivate(spi);
+	spi_release_bus(spi);
+	return ret;
+}
+
+static void mmc_spi_set_ios(struct mmc *mmc)
+{
+	struct spi_slave *spi = mmc->priv;
+	debug("%s: clock %u\n", __func__, mmc->clock);
+	if (mmc->clock)
+		spi_set_speed(spi, mmc->clock);
+}
+
+static int mmc_spi_init_p(struct mmc *mmc)
+{
+	struct spi_slave *spi = mmc->priv;
+	mmc->clock = 0;
+	spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
+	spi_claim_bus(spi);
+	/* cs deactivated for 100+ clock */
+	spi_xfer(spi, 18 * 8, NULL, NULL, 0);
+	spi_release_bus(spi);
+	return 0;
+}
+
+struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
+{
+	struct mmc *mmc;
+
+	mmc = malloc(sizeof(*mmc));
+	if (!mmc)
+		return NULL;
+	memset(mmc, 0, sizeof(*mmc));
+	mmc->priv = spi_setup_slave(bus, cs, speed, mode);
+	if (!mmc->priv) {
+		free(mmc);
+		return NULL;
+	}
+	sprintf(mmc->name, "MMC_SPI");
+	mmc->send_cmd = mmc_spi_request;
+	mmc->set_ios = mmc_spi_set_ios;
+	mmc->init = mmc_spi_init_p;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+	mmc->host_caps = MMC_MODE_SPI;
+
+	mmc->voltages = MMC_SPI_VOLTAGE;
+	mmc->f_max = speed;
+	mmc->f_min = MMC_SPI_MIN_CLOCK;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return mmc;
+}
diff --git a/marvell/uboot/drivers/mmc/mmc_write.c b/marvell/uboot/drivers/mmc/mmc_write.c
new file mode 100644
index 0000000..a655654
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mmc_write.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2008, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the Linux code
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <part.h>
+#include "mmc_private.h"
+
+static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
+{
+	struct mmc_cmd cmd;
+	ulong end;
+	int err, start_cmd, end_cmd;
+
+	if (mmc->high_capacity) {
+		end = start + blkcnt - 1;
+	} else {
+		end = (start + blkcnt - 1) * mmc->write_bl_len;
+		start *= mmc->write_bl_len;
+	}
+
+	if (IS_SD(mmc)) {
+		start_cmd = SD_CMD_ERASE_WR_BLK_START;
+		end_cmd = SD_CMD_ERASE_WR_BLK_END;
+	} else {
+		start_cmd = MMC_CMD_ERASE_GROUP_START;
+		end_cmd = MMC_CMD_ERASE_GROUP_END;
+	}
+
+	cmd.cmdidx = start_cmd;
+	cmd.cmdarg = start;
+	cmd.resp_type = MMC_RSP_R1;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err)
+		goto err_out;
+
+	cmd.cmdidx = end_cmd;
+	cmd.cmdarg = end;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err)
+		goto err_out;
+
+	cmd.cmdidx = MMC_CMD_ERASE;
+	cmd.cmdarg = SECURE_ERASE;
+	cmd.resp_type = MMC_RSP_R1b;
+
+	err = mmc_send_cmd(mmc, &cmd, NULL);
+	if (err)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	puts("mmc erase failed\n");
+	return err;
+}
+
+unsigned long mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
+{
+	int err = 0;
+	struct mmc *mmc = find_mmc_device(dev_num);
+	int timeout = 1000;
+
+	if (!mmc)
+		return -1;
+
+	if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
+		printf("\n\nCaution! Your devices Erase group is 0x%x\n"
+		       "The erase range would be change to "
+		       "0x" LBAF "~0x" LBAF "\n\n",
+		       mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
+		       ((start + blkcnt + mmc->erase_grp_size)
+		       & ~(mmc->erase_grp_size - 1)) - 1);
+
+	err = mmc_erase_t(mmc, start, blkcnt);
+	if (err)
+		return err;
+
+	/* Waiting for the ready status */
+	if (mmc_send_status(mmc, timeout))
+			return 0;
+
+	return blkcnt;
+}
+
+static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
+		lbaint_t blkcnt, const void *src)
+{
+	struct mmc_cmd cmd;
+	struct mmc_data data;
+	int timeout = 1000;
+
+	if ((start + blkcnt) > mmc->block_dev.lba) {
+		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
+		       start + blkcnt, mmc->block_dev.lba);
+		return 0;
+	}
+
+	if (blkcnt == 0)
+		return 0;
+	else if (blkcnt == 1)
+		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
+	else
+		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+
+	if (mmc->high_capacity)
+		cmd.cmdarg = start;
+	else
+		cmd.cmdarg = start * mmc->write_bl_len;
+
+	cmd.resp_type = MMC_RSP_R1;
+
+	data.src = src;
+	data.blocks = blkcnt;
+	data.blocksize = mmc->write_bl_len;
+	data.flags = MMC_DATA_WRITE;
+
+	if (mmc_send_cmd(mmc, &cmd, &data)) {
+		printf("mmc write failed\n");
+		return 0;
+	}
+
+	/* SPI multiblock writes terminate using a special
+	 * token, not a STOP_TRANSMISSION request.
+	 */
+	if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
+		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+		cmd.cmdarg = 0;
+		cmd.resp_type = MMC_RSP_R1b;
+		if (mmc_send_cmd(mmc, &cmd, NULL)) {
+			printf("mmc fail to send stop cmd\n");
+			return 0;
+		}
+	}
+
+	/* Waiting for the ready status */
+	if (mmc_send_status(mmc, timeout))
+		return 0;
+
+	return blkcnt;
+}
+
+ulong mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void *src)
+{
+	lbaint_t cur, blocks_todo = blkcnt;
+
+	struct mmc *mmc = find_mmc_device(dev_num);
+	if (!mmc)
+		return 0;
+
+	if (mmc_set_blocklen(mmc, mmc->write_bl_len))
+		return 0;
+
+	do {
+		cur = (blocks_todo > mmc->b_max) ?  mmc->b_max : blocks_todo;
+		if (mmc_write_blocks(mmc, start, cur, src) != cur)
+			return 0;
+		blocks_todo -= cur;
+		start += cur;
+		src += cur * mmc->write_bl_len;
+	} while (blocks_todo > 0);
+
+	return blkcnt;
+}
diff --git a/marvell/uboot/drivers/mmc/mv_sdhci.c b/marvell/uboot/drivers/mmc/mv_sdhci.c
new file mode 100644
index 0000000..63e1f90
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mv_sdhci.c
@@ -0,0 +1,55 @@
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+static struct sdhci_ops mv_ops;
+
+#if defined(CONFIG_SHEEVA_88SV331xV5)
+#define SD_CE_ATA_2	0xEA
+#define  MMC_CARD	0x1000
+#define  MMC_WIDTH	0x0100
+static inline void mv_sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	struct mmc *mmc = host->mmc;
+	u32 ata = (u32)host->ioaddr + SD_CE_ATA_2;
+
+	if (!IS_SD(mmc) && reg == SDHCI_HOST_CONTROL) {
+		if (mmc->bus_width == 8)
+			writew(readw(ata) | (MMC_CARD | MMC_WIDTH), ata);
+		else
+			writew(readw(ata) & ~(MMC_CARD | MMC_WIDTH), ata);
+	}
+
+	writeb(val, host->ioaddr + reg);
+}
+
+#else
+#define mv_sdhci_writeb	NULL
+#endif /* CONFIG_SHEEVA_88SV331xV5 */
+#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
+
+static char *MVSDH_NAME = "mv_sdh";
+int mv_sdh_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
+{
+	struct sdhci_host *host = NULL;
+	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+	if (!host) {
+		printf("sdh_host malloc fail!\n");
+		return 1;
+	}
+
+	host->name = MVSDH_NAME;
+	host->ioaddr = (void *)regbase;
+	host->quirks = quirks;
+#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+	memset(&mv_ops, 0, sizeof(struct sdhci_ops));
+	mv_ops.write_b = mv_sdhci_writeb;
+	host->ops = &mv_ops;
+#endif
+	if (quirks & SDHCI_QUIRK_REG32_RW)
+		host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+	else
+		host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+	return add_sdhci(host, max_clk, min_clk);
+}
diff --git a/marvell/uboot/drivers/mmc/mxcmmc.c b/marvell/uboot/drivers/mmc/mxcmmc.c
new file mode 100644
index 0000000..4f99617
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mxcmmc.c
@@ -0,0 +1,524 @@
+/*
+ *  This is a driver for the SDHC controller found in Freescale MX2/MX3
+ *  SoCs. It is basically the same hardware as found on MX1 (imxmmc.c).
+ *  Unlike the hardware found on MX1, this hardware just works and does
+ *  not need all the quirks found in imxmmc.c, hence the seperate driver.
+ *
+ *  Copyright (C) 2009 Ilya Yanok, <yanok@emcraft.com>
+ *  Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
+ *
+ *  derived from pxamci.c by Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+#define DRIVER_NAME "mxc-mmc"
+
+struct mxcmci_regs {
+	u32 str_stp_clk;
+	u32 status;
+	u32 clk_rate;
+	u32 cmd_dat_cont;
+	u32 res_to;
+	u32 read_to;
+	u32 blk_len;
+	u32 nob;
+	u32 rev_no;
+	u32 int_cntr;
+	u32 cmd;
+	u32 arg;
+	u32 pad;
+	u32 res_fifo;
+	u32 buffer_access;
+};
+
+#define STR_STP_CLK_RESET               (1 << 3)
+#define STR_STP_CLK_START_CLK           (1 << 1)
+#define STR_STP_CLK_STOP_CLK            (1 << 0)
+
+#define STATUS_CARD_INSERTION		(1 << 31)
+#define STATUS_CARD_REMOVAL		(1 << 30)
+#define STATUS_YBUF_EMPTY		(1 << 29)
+#define STATUS_XBUF_EMPTY		(1 << 28)
+#define STATUS_YBUF_FULL		(1 << 27)
+#define STATUS_XBUF_FULL		(1 << 26)
+#define STATUS_BUF_UND_RUN		(1 << 25)
+#define STATUS_BUF_OVFL			(1 << 24)
+#define STATUS_SDIO_INT_ACTIVE		(1 << 14)
+#define STATUS_END_CMD_RESP		(1 << 13)
+#define STATUS_WRITE_OP_DONE		(1 << 12)
+#define STATUS_DATA_TRANS_DONE		(1 << 11)
+#define STATUS_READ_OP_DONE		(1 << 11)
+#define STATUS_WR_CRC_ERROR_CODE_MASK	(3 << 10)
+#define STATUS_CARD_BUS_CLK_RUN		(1 << 8)
+#define STATUS_BUF_READ_RDY		(1 << 7)
+#define STATUS_BUF_WRITE_RDY		(1 << 6)
+#define STATUS_RESP_CRC_ERR		(1 << 5)
+#define STATUS_CRC_READ_ERR		(1 << 3)
+#define STATUS_CRC_WRITE_ERR		(1 << 2)
+#define STATUS_TIME_OUT_RESP		(1 << 1)
+#define STATUS_TIME_OUT_READ		(1 << 0)
+#define STATUS_ERR_MASK			0x2f
+
+#define CMD_DAT_CONT_CMD_RESP_LONG_OFF	(1 << 12)
+#define CMD_DAT_CONT_STOP_READWAIT	(1 << 11)
+#define CMD_DAT_CONT_START_READWAIT	(1 << 10)
+#define CMD_DAT_CONT_BUS_WIDTH_4	(2 << 8)
+#define CMD_DAT_CONT_INIT		(1 << 7)
+#define CMD_DAT_CONT_WRITE		(1 << 4)
+#define CMD_DAT_CONT_DATA_ENABLE	(1 << 3)
+#define CMD_DAT_CONT_RESPONSE_48BIT_CRC	(1 << 0)
+#define CMD_DAT_CONT_RESPONSE_136BIT	(2 << 0)
+#define CMD_DAT_CONT_RESPONSE_48BIT	(3 << 0)
+
+#define INT_SDIO_INT_WKP_EN		(1 << 18)
+#define INT_CARD_INSERTION_WKP_EN	(1 << 17)
+#define INT_CARD_REMOVAL_WKP_EN		(1 << 16)
+#define INT_CARD_INSERTION_EN		(1 << 15)
+#define INT_CARD_REMOVAL_EN		(1 << 14)
+#define INT_SDIO_IRQ_EN			(1 << 13)
+#define INT_DAT0_EN			(1 << 12)
+#define INT_BUF_READ_EN			(1 << 4)
+#define INT_BUF_WRITE_EN		(1 << 3)
+#define INT_END_CMD_RES_EN		(1 << 2)
+#define INT_WRITE_OP_DONE_EN		(1 << 1)
+#define INT_READ_OP_EN			(1 << 0)
+
+struct mxcmci_host {
+	struct mmc		*mmc;
+	struct mxcmci_regs	*base;
+	int			irq;
+	int			detect_irq;
+	int			dma;
+	int			do_dma;
+	unsigned int		power_mode;
+
+	struct mmc_cmd		*cmd;
+	struct mmc_data		*data;
+
+	unsigned int		dma_nents;
+	unsigned int		datasize;
+	unsigned int		dma_dir;
+
+	u16			rev_no;
+	unsigned int		cmdat;
+
+	int			clock;
+};
+
+static struct mxcmci_host mxcmci_host;
+static struct mxcmci_host *host = &mxcmci_host;
+
+static inline int mxcmci_use_dma(struct mxcmci_host *host)
+{
+	return host->do_dma;
+}
+
+static void mxcmci_softreset(struct mxcmci_host *host)
+{
+	int i;
+
+	/* reset sequence */
+	writel(STR_STP_CLK_RESET, &host->base->str_stp_clk);
+	writel(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
+			&host->base->str_stp_clk);
+
+	for (i = 0; i < 8; i++)
+		writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk);
+
+	writel(0xff, &host->base->res_to);
+}
+
+static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
+{
+	unsigned int nob = data->blocks;
+	unsigned int blksz = data->blocksize;
+	unsigned int datasize = nob * blksz;
+
+	host->data = data;
+
+	writel(nob, &host->base->nob);
+	writel(blksz, &host->base->blk_len);
+	host->datasize = datasize;
+}
+
+static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_cmd *cmd,
+		unsigned int cmdat)
+{
+	if (host->cmd != NULL)
+		printf("mxcmci: error!\n");
+	host->cmd = cmd;
+
+	switch (cmd->resp_type) {
+	case MMC_RSP_R1: /* short CRC, OPCODE */
+	case MMC_RSP_R1b:/* short CRC, OPCODE, BUSY */
+		cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC;
+		break;
+	case MMC_RSP_R2: /* long 136 bit + CRC */
+		cmdat |= CMD_DAT_CONT_RESPONSE_136BIT;
+		break;
+	case MMC_RSP_R3: /* short */
+		cmdat |= CMD_DAT_CONT_RESPONSE_48BIT;
+		break;
+	case MMC_RSP_NONE:
+		break;
+	default:
+		printf("mxcmci: unhandled response type 0x%x\n",
+				cmd->resp_type);
+		return -EINVAL;
+	}
+
+	writel(cmd->cmdidx, &host->base->cmd);
+	writel(cmd->cmdarg, &host->base->arg);
+	writel(cmdat, &host->base->cmd_dat_cont);
+
+	return 0;
+}
+
+static void mxcmci_finish_request(struct mxcmci_host *host,
+		struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	host->cmd = NULL;
+	host->data = NULL;
+}
+
+static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
+{
+	int data_error = 0;
+
+	if (stat & STATUS_ERR_MASK) {
+		printf("request failed. status: 0x%08x\n",
+				stat);
+		if (stat & STATUS_CRC_READ_ERR) {
+			data_error = -EILSEQ;
+		} else if (stat & STATUS_CRC_WRITE_ERR) {
+			u32 err_code = (stat >> 9) & 0x3;
+			if (err_code == 2) /* No CRC response */
+				data_error = TIMEOUT;
+			else
+				data_error = -EILSEQ;
+		} else if (stat & STATUS_TIME_OUT_READ) {
+			data_error = TIMEOUT;
+		} else {
+			data_error = -EIO;
+		}
+	}
+
+	host->data = NULL;
+
+	return data_error;
+}
+
+static int mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
+{
+	struct mmc_cmd *cmd = host->cmd;
+	int i;
+	u32 a, b, c;
+	u32 *resp = (u32 *)cmd->response;
+
+	if (!cmd)
+		return 0;
+
+	if (stat & STATUS_TIME_OUT_RESP) {
+		printf("CMD TIMEOUT\n");
+		return TIMEOUT;
+	} else if (stat & STATUS_RESP_CRC_ERR && cmd->resp_type & MMC_RSP_CRC) {
+		printf("cmd crc error\n");
+		return -EILSEQ;
+	}
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		if (cmd->resp_type & MMC_RSP_136) {
+			for (i = 0; i < 4; i++) {
+				a = readl(&host->base->res_fifo) & 0xFFFF;
+				b = readl(&host->base->res_fifo) & 0xFFFF;
+				resp[i] = a << 16 | b;
+			}
+		} else {
+			a = readl(&host->base->res_fifo) & 0xFFFF;
+			b = readl(&host->base->res_fifo) & 0xFFFF;
+			c = readl(&host->base->res_fifo) & 0xFFFF;
+			resp[0] = a << 24 | b << 8 | c >> 8;
+		}
+	}
+	return 0;
+}
+
+static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
+{
+	u32 stat;
+	unsigned long timeout = get_ticks() + CONFIG_SYS_HZ;
+
+	do {
+		stat = readl(&host->base->status);
+		if (stat & STATUS_ERR_MASK)
+			return stat;
+		if (timeout < get_ticks())
+			return STATUS_TIME_OUT_READ;
+		if (stat & mask)
+			return 0;
+	} while (1);
+}
+
+static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
+{
+	unsigned int stat;
+	u32 *buf = _buf;
+
+	while (bytes > 3) {
+		stat = mxcmci_poll_status(host,
+				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
+		if (stat)
+			return stat;
+		*buf++ = readl(&host->base->buffer_access);
+		bytes -= 4;
+	}
+
+	if (bytes) {
+		u8 *b = (u8 *)buf;
+		u32 tmp;
+
+		stat = mxcmci_poll_status(host,
+				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
+		if (stat)
+			return stat;
+		tmp = readl(&host->base->buffer_access);
+		memcpy(b, &tmp, bytes);
+	}
+
+	return 0;
+}
+
+static int mxcmci_push(struct mxcmci_host *host, const void *_buf, int bytes)
+{
+	unsigned int stat;
+	const u32 *buf = _buf;
+
+	while (bytes > 3) {
+		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+		if (stat)
+			return stat;
+		writel(*buf++, &host->base->buffer_access);
+		bytes -= 4;
+	}
+
+	if (bytes) {
+		const u8 *b = (u8 *)buf;
+		u32 tmp;
+
+		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+		if (stat)
+			return stat;
+
+		memcpy(&tmp, b, bytes);
+		writel(tmp, &host->base->buffer_access);
+	}
+
+	stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
+	if (stat)
+		return stat;
+
+	return 0;
+}
+
+static int mxcmci_transfer_data(struct mxcmci_host *host)
+{
+	struct mmc_data *data = host->data;
+	int stat;
+	unsigned long length;
+
+	length = data->blocks * data->blocksize;
+	host->datasize = 0;
+
+	if (data->flags & MMC_DATA_READ) {
+		stat = mxcmci_pull(host, data->dest, length);
+		if (stat)
+			return stat;
+		host->datasize += length;
+	} else {
+		stat = mxcmci_push(host, (const void *)(data->src), length);
+		if (stat)
+			return stat;
+		host->datasize += length;
+		stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
+		if (stat)
+			return stat;
+	}
+	return 0;
+}
+
+static int mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
+{
+	int datastat;
+	int ret;
+
+	ret = mxcmci_read_response(host, stat);
+
+	if (ret) {
+		mxcmci_finish_request(host, host->cmd, host->data);
+		return ret;
+	}
+
+	if (!host->data) {
+		mxcmci_finish_request(host, host->cmd, host->data);
+		return 0;
+	}
+
+	datastat = mxcmci_transfer_data(host);
+	ret = mxcmci_finish_data(host, datastat);
+	mxcmci_finish_request(host, host->cmd, host->data);
+	return ret;
+}
+
+static int mxcmci_request(struct mmc *mmc, struct mmc_cmd *cmd,
+		struct mmc_data *data)
+{
+	struct mxcmci_host *host = mmc->priv;
+	unsigned int cmdat = host->cmdat;
+	u32 stat;
+	int ret;
+
+	host->cmdat &= ~CMD_DAT_CONT_INIT;
+	if (data) {
+		mxcmci_setup_data(host, data);
+
+		cmdat |= CMD_DAT_CONT_DATA_ENABLE;
+
+		if (data->flags & MMC_DATA_WRITE)
+			cmdat |= CMD_DAT_CONT_WRITE;
+	}
+
+	if ((ret = mxcmci_start_cmd(host, cmd, cmdat))) {
+		mxcmci_finish_request(host, cmd, data);
+		return ret;
+	}
+
+	do {
+		stat = readl(&host->base->status);
+		writel(stat, &host->base->status);
+	} while (!(stat & STATUS_END_CMD_RESP));
+
+	return mxcmci_cmd_done(host, stat);
+}
+
+static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
+{
+	unsigned int divider;
+	int prescaler = 0;
+	unsigned long clk_in = mxc_get_clock(MXC_ESDHC_CLK);
+
+	while (prescaler <= 0x800) {
+		for (divider = 1; divider <= 0xF; divider++) {
+			int x;
+
+			x = (clk_in / (divider + 1));
+
+			if (prescaler)
+				x /= (prescaler * 2);
+
+			if (x <= clk_ios)
+				break;
+		}
+		if (divider < 0x10)
+			break;
+
+		if (prescaler == 0)
+			prescaler = 1;
+		else
+			prescaler <<= 1;
+	}
+
+	writel((prescaler << 4) | divider, &host->base->clk_rate);
+}
+
+static void mxcmci_set_ios(struct mmc *mmc)
+{
+	struct mxcmci_host *host = mmc->priv;
+	if (mmc->bus_width == 4)
+		host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
+	else
+		host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
+
+	if (mmc->clock) {
+		mxcmci_set_clk_rate(host, mmc->clock);
+		writel(STR_STP_CLK_START_CLK, &host->base->str_stp_clk);
+	} else {
+		writel(STR_STP_CLK_STOP_CLK, &host->base->str_stp_clk);
+	}
+
+	host->clock = mmc->clock;
+}
+
+static int mxcmci_init(struct mmc *mmc)
+{
+	struct mxcmci_host *host = mmc->priv;
+
+	mxcmci_softreset(host);
+
+	host->rev_no = readl(&host->base->rev_no);
+	if (host->rev_no != 0x400) {
+		printf("wrong rev.no. 0x%08x. aborting.\n",
+			host->rev_no);
+		return -ENODEV;
+	}
+
+	/* recommended in data sheet */
+	writel(0x2db4, &host->base->read_to);
+
+	writel(0, &host->base->int_cntr);
+
+	return 0;
+}
+
+static int mxcmci_initialize(bd_t *bis)
+{
+	struct mmc *mmc = NULL;
+
+	mmc = malloc(sizeof(struct mmc));
+
+	if (!mmc)
+		return -ENOMEM;
+
+	sprintf(mmc->name, "MXC MCI");
+	mmc->send_cmd = mxcmci_request;
+	mmc->set_ios = mxcmci_set_ios;
+	mmc->init = mxcmci_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+	mmc->host_caps = MMC_MODE_4BIT;
+
+	host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE;
+	mmc->priv = host;
+	host->mmc = mmc;
+
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	mmc->f_min = mxc_get_clock(MXC_ESDHC_CLK) >> 7;
+	mmc->f_max = mxc_get_clock(MXC_ESDHC_CLK) >> 1;
+
+	mmc->b_max = 0;
+
+	mmc_register(mmc);
+
+	return 0;
+}
+
+int mxc_mmc_init(bd_t *bis)
+{
+	return mxcmci_initialize(bis);
+}
diff --git a/marvell/uboot/drivers/mmc/mxsmmc.c b/marvell/uboot/drivers/mmc/mxsmmc.c
new file mode 100644
index 0000000..245f9d0
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/mxsmmc.c
@@ -0,0 +1,428 @@
+/*
+ * Freescale i.MX28 SSP MMC driver
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * Based on code from LTIB:
+ * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Terry Lv
+ *
+ * Copyright 2007, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the pxa mmc code:
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/imx-common/dma.h>
+#include <bouncebuf.h>
+
+struct mxsmmc_priv {
+	int			id;
+	struct mxs_ssp_regs	*regs;
+	uint32_t		buswidth;
+	int			(*mmc_is_wp)(int);
+	int			(*mmc_cd)(int);
+	struct mxs_dma_desc	*desc;
+};
+
+#define	MXSMMC_MAX_TIMEOUT	10000
+#define MXSMMC_SMALL_TRANSFER	512
+
+static int mxsmmc_cd(struct mxsmmc_priv *priv)
+{
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+
+	if (priv->mmc_cd)
+		return priv->mmc_cd(priv->id);
+
+	return !(readl(&ssp_regs->hw_ssp_status) & SSP_STATUS_CARD_DETECT);
+}
+
+static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data)
+{
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+	uint32_t *data_ptr;
+	int timeout = MXSMMC_MAX_TIMEOUT;
+	uint32_t reg;
+	uint32_t data_count = data->blocksize * data->blocks;
+
+	if (data->flags & MMC_DATA_READ) {
+		data_ptr = (uint32_t *)data->dest;
+		while (data_count && --timeout) {
+			reg = readl(&ssp_regs->hw_ssp_status);
+			if (!(reg & SSP_STATUS_FIFO_EMPTY)) {
+				*data_ptr++ = readl(&ssp_regs->hw_ssp_data);
+				data_count -= 4;
+				timeout = MXSMMC_MAX_TIMEOUT;
+			} else
+				udelay(1000);
+		}
+	} else {
+		data_ptr = (uint32_t *)data->src;
+		timeout *= 100;
+		while (data_count && --timeout) {
+			reg = readl(&ssp_regs->hw_ssp_status);
+			if (!(reg & SSP_STATUS_FIFO_FULL)) {
+				writel(*data_ptr++, &ssp_regs->hw_ssp_data);
+				data_count -= 4;
+				timeout = MXSMMC_MAX_TIMEOUT;
+			} else
+				udelay(1000);
+		}
+	}
+
+	return timeout ? 0 : COMM_ERR;
+}
+
+static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
+{
+	uint32_t data_count = data->blocksize * data->blocks;
+	int dmach;
+	struct mxs_dma_desc *desc = priv->desc;
+	void *addr;
+	unsigned int flags;
+	struct bounce_buffer bbstate;
+
+	memset(desc, 0, sizeof(struct mxs_dma_desc));
+	desc->address = (dma_addr_t)desc;
+
+	if (data->flags & MMC_DATA_READ) {
+		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE;
+		addr = data->dest;
+		flags = GEN_BB_WRITE;
+	} else {
+		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ;
+		addr = (void *)data->src;
+		flags = GEN_BB_READ;
+	}
+
+	bounce_buffer_start(&bbstate, addr, data_count, flags);
+
+	priv->desc->cmd.address = (dma_addr_t)bbstate.bounce_buffer;
+
+	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
+				(data_count << MXS_DMA_DESC_BYTES_OFFSET);
+
+	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id;
+	mxs_dma_desc_append(dmach, priv->desc);
+	if (mxs_dma_go(dmach)) {
+		bounce_buffer_stop(&bbstate);
+		return COMM_ERR;
+	}
+
+	bounce_buffer_stop(&bbstate);
+
+	return 0;
+}
+
+/*
+ * Sends a command out on the bus.  Takes the mmc pointer,
+ * a command pointer, and an optional data pointer.
+ */
+static int
+mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+	uint32_t reg;
+	int timeout;
+	uint32_t ctrl0;
+	int ret;
+
+	debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx);
+
+	/* Check bus busy */
+	timeout = MXSMMC_MAX_TIMEOUT;
+	while (--timeout) {
+		udelay(1000);
+		reg = readl(&ssp_regs->hw_ssp_status);
+		if (!(reg &
+			(SSP_STATUS_BUSY | SSP_STATUS_DATA_BUSY |
+			SSP_STATUS_CMD_BUSY))) {
+			break;
+		}
+	}
+
+	if (!timeout) {
+		printf("MMC%d: Bus busy timeout!\n", mmc->block_dev.dev);
+		return TIMEOUT;
+	}
+
+	/* See if card is present */
+	if (!mxsmmc_cd(priv)) {
+		printf("MMC%d: No card detected!\n", mmc->block_dev.dev);
+		return NO_CARD_ERR;
+	}
+
+	/* Start building CTRL0 contents */
+	ctrl0 = priv->buswidth;
+
+	/* Set up command */
+	if (!(cmd->resp_type & MMC_RSP_CRC))
+		ctrl0 |= SSP_CTRL0_IGNORE_CRC;
+	if (cmd->resp_type & MMC_RSP_PRESENT)	/* Need to get response */
+		ctrl0 |= SSP_CTRL0_GET_RESP;
+	if (cmd->resp_type & MMC_RSP_136)	/* It's a 136 bits response */
+		ctrl0 |= SSP_CTRL0_LONG_RESP;
+
+	if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER))
+		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr);
+	else
+		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set);
+
+	/* Command index */
+	reg = readl(&ssp_regs->hw_ssp_cmd0);
+	reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC);
+	reg |= cmd->cmdidx << SSP_CMD0_CMD_OFFSET;
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		reg |= SSP_CMD0_APPEND_8CYC;
+	writel(reg, &ssp_regs->hw_ssp_cmd0);
+
+	/* Command argument */
+	writel(cmd->cmdarg, &ssp_regs->hw_ssp_cmd1);
+
+	/* Set up data */
+	if (data) {
+		/* READ or WRITE */
+		if (data->flags & MMC_DATA_READ) {
+			ctrl0 |= SSP_CTRL0_READ;
+		} else if (priv->mmc_is_wp &&
+			priv->mmc_is_wp(mmc->block_dev.dev)) {
+			printf("MMC%d: Can not write a locked card!\n",
+				mmc->block_dev.dev);
+			return UNUSABLE_ERR;
+		}
+
+		ctrl0 |= SSP_CTRL0_DATA_XFER;
+
+		reg = data->blocksize * data->blocks;
+#if defined(CONFIG_MX23)
+		ctrl0 |= reg & SSP_CTRL0_XFER_COUNT_MASK;
+
+		clrsetbits_le32(&ssp_regs->hw_ssp_cmd0,
+			SSP_CMD0_BLOCK_SIZE_MASK | SSP_CMD0_BLOCK_COUNT_MASK,
+			((data->blocks - 1) << SSP_CMD0_BLOCK_COUNT_OFFSET) |
+			((ffs(data->blocksize) - 1) <<
+				SSP_CMD0_BLOCK_SIZE_OFFSET));
+#elif defined(CONFIG_MX28)
+		writel(reg, &ssp_regs->hw_ssp_xfer_size);
+
+		reg = ((data->blocks - 1) <<
+			SSP_BLOCK_SIZE_BLOCK_COUNT_OFFSET) |
+			((ffs(data->blocksize) - 1) <<
+			SSP_BLOCK_SIZE_BLOCK_SIZE_OFFSET);
+		writel(reg, &ssp_regs->hw_ssp_block_size);
+#endif
+	}
+
+	/* Kick off the command */
+	ctrl0 |= SSP_CTRL0_WAIT_FOR_IRQ | SSP_CTRL0_ENABLE | SSP_CTRL0_RUN;
+	writel(ctrl0, &ssp_regs->hw_ssp_ctrl0);
+
+	/* Wait for the command to complete */
+	timeout = MXSMMC_MAX_TIMEOUT;
+	while (--timeout) {
+		udelay(1000);
+		reg = readl(&ssp_regs->hw_ssp_status);
+		if (!(reg & SSP_STATUS_CMD_BUSY))
+			break;
+	}
+
+	if (!timeout) {
+		printf("MMC%d: Command %d busy\n",
+			mmc->block_dev.dev, cmd->cmdidx);
+		return TIMEOUT;
+	}
+
+	/* Check command timeout */
+	if (reg & SSP_STATUS_RESP_TIMEOUT) {
+		printf("MMC%d: Command %d timeout (status 0x%08x)\n",
+			mmc->block_dev.dev, cmd->cmdidx, reg);
+		return TIMEOUT;
+	}
+
+	/* Check command errors */
+	if (reg & (SSP_STATUS_RESP_CRC_ERR | SSP_STATUS_RESP_ERR)) {
+		printf("MMC%d: Command %d error (status 0x%08x)!\n",
+			mmc->block_dev.dev, cmd->cmdidx, reg);
+		return COMM_ERR;
+	}
+
+	/* Copy response to response buffer */
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[3] = readl(&ssp_regs->hw_ssp_sdresp0);
+		cmd->response[2] = readl(&ssp_regs->hw_ssp_sdresp1);
+		cmd->response[1] = readl(&ssp_regs->hw_ssp_sdresp2);
+		cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp3);
+	} else
+		cmd->response[0] = readl(&ssp_regs->hw_ssp_sdresp0);
+
+	/* Return if no data to process */
+	if (!data)
+		return 0;
+
+	if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) {
+		ret = mxsmmc_send_cmd_pio(priv, data);
+		if (ret) {
+			printf("MMC%d: Data timeout with command %d "
+				"(status 0x%08x)!\n",
+				mmc->block_dev.dev, cmd->cmdidx, reg);
+			return ret;
+		}
+	} else {
+		ret = mxsmmc_send_cmd_dma(priv, data);
+		if (ret) {
+			printf("MMC%d: DMA transfer failed\n",
+				mmc->block_dev.dev);
+			return ret;
+		}
+	}
+
+	/* Check data errors */
+	reg = readl(&ssp_regs->hw_ssp_status);
+	if (reg &
+		(SSP_STATUS_TIMEOUT | SSP_STATUS_DATA_CRC_ERR |
+		SSP_STATUS_FIFO_OVRFLW | SSP_STATUS_FIFO_UNDRFLW)) {
+		printf("MMC%d: Data error with command %d (status 0x%08x)!\n",
+			mmc->block_dev.dev, cmd->cmdidx, reg);
+		return COMM_ERR;
+	}
+
+	return 0;
+}
+
+static void mxsmmc_set_ios(struct mmc *mmc)
+{
+	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+
+	/* Set the clock speed */
+	if (mmc->clock)
+		mxs_set_ssp_busclock(priv->id, mmc->clock / 1000);
+
+	switch (mmc->bus_width) {
+	case 1:
+		priv->buswidth = SSP_CTRL0_BUS_WIDTH_ONE_BIT;
+		break;
+	case 4:
+		priv->buswidth = SSP_CTRL0_BUS_WIDTH_FOUR_BIT;
+		break;
+	case 8:
+		priv->buswidth = SSP_CTRL0_BUS_WIDTH_EIGHT_BIT;
+		break;
+	}
+
+	/* Set the bus width */
+	clrsetbits_le32(&ssp_regs->hw_ssp_ctrl0,
+			SSP_CTRL0_BUS_WIDTH_MASK, priv->buswidth);
+
+	debug("MMC%d: Set %d bits bus width\n",
+		mmc->block_dev.dev, mmc->bus_width);
+}
+
+static int mxsmmc_init(struct mmc *mmc)
+{
+	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv;
+	struct mxs_ssp_regs *ssp_regs = priv->regs;
+
+	/* Reset SSP */
+	mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);
+
+	/* Reconfigure the SSP block for MMC operation */
+	writel(SSP_CTRL1_SSP_MODE_SD_MMC |
+		SSP_CTRL1_WORD_LENGTH_EIGHT_BITS |
+		SSP_CTRL1_DMA_ENABLE |
+		SSP_CTRL1_POLARITY |
+		SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
+		SSP_CTRL1_DATA_CRC_IRQ_EN |
+		SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
+		SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
+		SSP_CTRL1_RESP_ERR_IRQ_EN,
+		&ssp_regs->hw_ssp_ctrl1_set);
+
+	/* Set initial bit clock 400 KHz */
+	mxs_set_ssp_busclock(priv->id, 400);
+
+	/* Send initial 74 clock cycles (185 us @ 400 KHz)*/
+	writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_set);
+	udelay(200);
+	writel(SSP_CMD0_CONT_CLKING_EN, &ssp_regs->hw_ssp_cmd0_clr);
+
+	return 0;
+}
+
+int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
+{
+	struct mmc *mmc = NULL;
+	struct mxsmmc_priv *priv = NULL;
+	int ret;
+	const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id);
+
+	if (!mxs_ssp_bus_id_valid(id))
+		return -ENODEV;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+
+	priv = malloc(sizeof(struct mxsmmc_priv));
+	if (!priv) {
+		free(mmc);
+		return -ENOMEM;
+	}
+
+	priv->desc = mxs_dma_desc_alloc();
+	if (!priv->desc) {
+		free(priv);
+		free(mmc);
+		return -ENOMEM;
+	}
+
+	ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);
+	if (ret)
+		return ret;
+
+	priv->mmc_is_wp = wp;
+	priv->mmc_cd = cd;
+	priv->id = id;
+	priv->regs = mxs_ssp_regs_by_bus(id);
+
+	sprintf(mmc->name, "MXS MMC");
+	mmc->send_cmd = mxsmmc_send_cmd;
+	mmc->set_ios = mxsmmc_set_ios;
+	mmc->init = mxsmmc_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+	mmc->priv = priv;
+
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT |
+			 MMC_MODE_HS_52MHz | MMC_MODE_HS |
+			 MMC_MODE_HC;
+
+	/*
+	 * SSPCLK = 480 * 18 / 29 / 1 = 297.731 MHz
+	 * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
+	 * CLOCK_DIVIDE has to be an even value from 2 to 254, and
+	 * CLOCK_RATE could be any integer from 0 to 255.
+	 */
+	mmc->f_min = 400000;
+	mmc->f_max = mxc_get_clock(MXC_SSP0_CLK + mxsmmc_clk_id) * 1000 / 2;
+	mmc->b_max = 0x20;
+
+	mmc_register(mmc);
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/omap_hsmmc.c b/marvell/uboot/drivers/mmc/omap_hsmmc.c
new file mode 100644
index 0000000..d3a8b53
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/omap_hsmmc.c
@@ -0,0 +1,688 @@
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Sukumar Ghorai <s-ghorai@ti.com>
+ *
+ * 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's version 2 of
+ * the License.
+ *
+ * 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 <part.h>
+#include <i2c.h>
+#include <twl4030.h>
+#include <twl6030.h>
+#include <palmas.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/mmc_host_def.h>
+#include <asm/arch/sys_proto.h>
+
+/* common definitions for all OMAPs */
+#define SYSCTL_SRC	(1 << 25)
+#define SYSCTL_SRD	(1 << 26)
+
+struct omap_hsmmc_data {
+	struct hsmmc *base_addr;
+	int cd_gpio;
+	int wp_gpio;
+};
+
+/* If we fail after 1 second wait, something is really bad */
+#define MAX_RETRY_MS	1000
+
+static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
+static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
+			unsigned int siz);
+static struct mmc hsmmc_dev[3];
+static struct omap_hsmmc_data hsmmc_dev_data[3];
+
+#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
+	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
+static int omap_mmc_setup_gpio_in(int gpio, const char *label)
+{
+	if (!gpio_is_valid(gpio))
+		return -1;
+
+	if (gpio_request(gpio, label) < 0)
+		return -1;
+
+	if (gpio_direction_input(gpio) < 0)
+		return -1;
+
+	return gpio;
+}
+
+static int omap_mmc_getcd(struct mmc *mmc)
+{
+	int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
+	return gpio_get_value(cd_gpio);
+}
+
+static int omap_mmc_getwp(struct mmc *mmc)
+{
+	int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio;
+	return gpio_get_value(wp_gpio);
+}
+#else
+static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
+{
+	return -1;
+}
+
+#define omap_mmc_getcd NULL
+#define omap_mmc_getwp NULL
+#endif
+
+#if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
+static void omap4_vmmc_pbias_config(struct mmc *mmc)
+{
+	u32 value = 0;
+
+	value = readl((*ctrl)->control_pbiaslite);
+	value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
+	writel(value, (*ctrl)->control_pbiaslite);
+	/* set VMMC to 3V */
+	twl6030_power_mmc_init();
+	value = readl((*ctrl)->control_pbiaslite);
+	value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
+	writel(value, (*ctrl)->control_pbiaslite);
+}
+#endif
+
+#if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
+static void omap5_pbias_config(struct mmc *mmc)
+{
+	u32 value = 0;
+
+	value = readl((*ctrl)->control_pbias);
+	value &= ~SDCARD_PWRDNZ;
+	writel(value, (*ctrl)->control_pbias);
+	udelay(10); /* wait 10 us */
+	value &= ~SDCARD_BIAS_PWRDNZ;
+	writel(value, (*ctrl)->control_pbias);
+
+	palmas_mmc1_poweron_ldo();
+
+	value = readl((*ctrl)->control_pbias);
+	value |= SDCARD_BIAS_PWRDNZ;
+	writel(value, (*ctrl)->control_pbias);
+	udelay(150); /* wait 150 us */
+	value |= SDCARD_PWRDNZ;
+	writel(value, (*ctrl)->control_pbias);
+	udelay(150); /* wait 150 us */
+}
+#endif
+
+unsigned char mmc_board_init(struct mmc *mmc)
+{
+#if defined(CONFIG_OMAP34XX)
+	t2_t *t2_base = (t2_t *)T2_BASE;
+	struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+	u32 pbias_lite;
+
+	pbias_lite = readl(&t2_base->pbias_lite);
+	pbias_lite &= ~(PBIASLITEPWRDNZ1 | PBIASLITEPWRDNZ0);
+	writel(pbias_lite, &t2_base->pbias_lite);
+#endif
+#if defined(CONFIG_TWL4030_POWER)
+	twl4030_power_mmc_init();
+	mdelay(100);	/* ramp-up delay from Linux code */
+#endif
+#if defined(CONFIG_OMAP34XX)
+	writel(pbias_lite | PBIASLITEPWRDNZ1 |
+		PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
+		&t2_base->pbias_lite);
+
+	writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
+		&t2_base->devconf0);
+
+	writel(readl(&t2_base->devconf1) | MMCSDIO2ADPCLKISEL,
+		&t2_base->devconf1);
+
+	/* Change from default of 52MHz to 26MHz if necessary */
+	if (!(mmc->host_caps & MMC_MODE_HS_52MHz))
+		writel(readl(&t2_base->ctl_prog_io1) & ~CTLPROGIO1SPEEDCTRL,
+			&t2_base->ctl_prog_io1);
+
+	writel(readl(&prcm_base->fclken1_core) |
+		EN_MMC1 | EN_MMC2 | EN_MMC3,
+		&prcm_base->fclken1_core);
+
+	writel(readl(&prcm_base->iclken1_core) |
+		EN_MMC1 | EN_MMC2 | EN_MMC3,
+		&prcm_base->iclken1_core);
+#endif
+
+#if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
+	/* PBIAS config needed for MMC1 only */
+	if (mmc->block_dev.dev == 0)
+		omap4_vmmc_pbias_config(mmc);
+#endif
+#if defined(CONFIG_OMAP54XX) && defined(CONFIG_PALMAS_POWER)
+	if (mmc->block_dev.dev == 0)
+		omap5_pbias_config(mmc);
+#endif
+
+	return 0;
+}
+
+void mmc_init_stream(struct hsmmc *mmc_base)
+{
+	ulong start;
+
+	writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
+
+	writel(MMC_CMD0, &mmc_base->cmd);
+	start = get_timer(0);
+	while (!(readl(&mmc_base->stat) & CC_MASK)) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for cc!\n", __func__);
+			return;
+		}
+	}
+	writel(CC_MASK, &mmc_base->stat)
+		;
+	writel(MMC_CMD0, &mmc_base->cmd)
+		;
+	start = get_timer(0);
+	while (!(readl(&mmc_base->stat) & CC_MASK)) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for cc2!\n", __func__);
+			return;
+		}
+	}
+	writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
+}
+
+
+static int mmc_init_setup(struct mmc *mmc)
+{
+	struct hsmmc *mmc_base;
+	unsigned int reg_val;
+	unsigned int dsor;
+	ulong start;
+
+	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
+	mmc_board_init(mmc);
+
+	writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
+		&mmc_base->sysconfig);
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for cc2!\n", __func__);
+			return TIMEOUT;
+		}
+	}
+	writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for softresetall!\n",
+				__func__);
+			return TIMEOUT;
+		}
+	}
+	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
+	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
+		&mmc_base->capa);
+
+	reg_val = readl(&mmc_base->con) & RESERVED_MASK;
+
+	writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
+		MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
+		HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
+
+	dsor = 240;
+	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+		(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+		(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for ics!\n", __func__);
+			return TIMEOUT;
+		}
+	}
+	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+
+	writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
+
+	writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
+		IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
+		&mmc_base->ie);
+
+	mmc_init_stream(mmc_base);
+
+	return 0;
+}
+
+/*
+ * MMC controller internal finite state machine reset
+ *
+ * Used to reset command or data internal state machines, using respectively
+ * SRC or SRD bit of SYSCTL register
+ */
+static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
+{
+	ulong start;
+
+	mmc_reg_out(&mmc_base->sysctl, bit, bit);
+
+	/*
+	 * CMD(DAT) lines reset procedures are slightly different
+	 * for OMAP3 and OMAP4(AM335x,OMAP5,DRA7xx).
+	 * According to OMAP3 TRM:
+	 * Set SRC(SRD) bit in MMCHS_SYSCTL register to 0x1 and wait until it
+	 * returns to 0x0.
+	 * According to OMAP4(AM335x,OMAP5,DRA7xx) TRMs, CMD(DATA) lines reset
+	 * procedure steps must be as follows:
+	 * 1. Initiate CMD(DAT) line reset by writing 0x1 to SRC(SRD) bit in
+	 *    MMCHS_SYSCTL register (SD_SYSCTL for AM335x).
+	 * 2. Poll the SRC(SRD) bit until it is set to 0x1.
+	 * 3. Wait until the SRC (SRD) bit returns to 0x0
+	 *    (reset procedure is completed).
+	 */
+#if defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
+	defined(CONFIG_AM33XX)
+	if (!(readl(&mmc_base->sysctl) & bit)) {
+		start = get_timer(0);
+		while (!(readl(&mmc_base->sysctl) & bit)) {
+			if (get_timer(0) - start > MAX_RETRY_MS)
+				return;
+		}
+	}
+#endif
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysctl) & bit) != 0) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for sysctl %x to clear\n",
+				__func__, bit);
+			return;
+		}
+	}
+}
+
+static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data)
+{
+	struct hsmmc *mmc_base;
+	unsigned int flags, mmc_stat;
+	ulong start;
+
+	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
+	start = get_timer(0);
+	while ((readl(&mmc_base->pstate) & (DATI_MASK | CMDI_MASK)) != 0) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting on cmd inhibit to clear\n",
+					__func__);
+			return TIMEOUT;
+		}
+	}
+	writel(0xFFFFFFFF, &mmc_base->stat);
+	start = get_timer(0);
+	while (readl(&mmc_base->stat)) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for STAT (%x) to clear\n",
+				__func__, readl(&mmc_base->stat));
+			return TIMEOUT;
+		}
+	}
+	/*
+	 * CMDREG
+	 * CMDIDX[13:8]	: Command index
+	 * DATAPRNT[5]	: Data Present Select
+	 * ENCMDIDX[4]	: Command Index Check Enable
+	 * ENCMDCRC[3]	: Command CRC Check Enable
+	 * RSPTYP[1:0]
+	 *	00 = No Response
+	 *	01 = Length 136
+	 *	10 = Length 48
+	 *	11 = Length 48 Check busy after response
+	 */
+	/* Delay added before checking the status of frq change
+	 * retry not supported by mmc.c(core file)
+	 */
+	if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
+		udelay(50000); /* wait 50 ms */
+
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		flags = 0;
+	else if (cmd->resp_type & MMC_RSP_136)
+		flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		flags = RSP_TYPE_LGHT48B;
+	else
+		flags = RSP_TYPE_LGHT48;
+
+	/* enable default flags */
+	flags =	flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
+			MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		flags |= CCCE_CHECK;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		flags |= CICE_CHECK;
+
+	if (data) {
+		if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+			 (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
+			flags |= (MSBS_MULTIBLK | BCE_ENABLE);
+			data->blocksize = 512;
+			writel(data->blocksize | (data->blocks << 16),
+							&mmc_base->blk);
+		} else
+			writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
+
+		if (data->flags & MMC_DATA_READ)
+			flags |= (DP_DATA | DDIR_READ);
+		else
+			flags |= (DP_DATA | DDIR_WRITE);
+	}
+
+	writel(cmd->cmdarg, &mmc_base->arg);
+	udelay(20);		/* To fix "No status update" error on eMMC */
+	writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
+
+	start = get_timer(0);
+	do {
+		mmc_stat = readl(&mmc_base->stat);
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s : timeout: No status update\n", __func__);
+			return TIMEOUT;
+		}
+	} while (!mmc_stat);
+
+	if ((mmc_stat & IE_CTO) != 0) {
+		mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
+		return TIMEOUT;
+	} else if ((mmc_stat & ERRI_MASK) != 0)
+		return -1;
+
+	if (mmc_stat & CC_MASK) {
+		writel(CC_MASK, &mmc_base->stat);
+		if (cmd->resp_type & MMC_RSP_PRESENT) {
+			if (cmd->resp_type & MMC_RSP_136) {
+				/* response type 2 */
+				cmd->response[3] = readl(&mmc_base->rsp10);
+				cmd->response[2] = readl(&mmc_base->rsp32);
+				cmd->response[1] = readl(&mmc_base->rsp54);
+				cmd->response[0] = readl(&mmc_base->rsp76);
+			} else
+				/* response types 1, 1b, 3, 4, 5, 6 */
+				cmd->response[0] = readl(&mmc_base->rsp10);
+		}
+	}
+
+	if (data && (data->flags & MMC_DATA_READ)) {
+		mmc_read_data(mmc_base,	data->dest,
+				data->blocksize * data->blocks);
+	} else if (data && (data->flags & MMC_DATA_WRITE)) {
+		mmc_write_data(mmc_base, data->src,
+				data->blocksize * data->blocks);
+	}
+	return 0;
+}
+
+static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size)
+{
+	unsigned int *output_buf = (unsigned int *)buf;
+	unsigned int mmc_stat;
+	unsigned int count;
+
+	/*
+	 * Start Polled Read
+	 */
+	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+	count /= 4;
+
+	while (size) {
+		ulong start = get_timer(0);
+		do {
+			mmc_stat = readl(&mmc_base->stat);
+			if (get_timer(0) - start > MAX_RETRY_MS) {
+				printf("%s: timedout waiting for status!\n",
+						__func__);
+				return TIMEOUT;
+			}
+		} while (mmc_stat == 0);
+
+		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
+			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
+
+		if ((mmc_stat & ERRI_MASK) != 0)
+			return 1;
+
+		if (mmc_stat & BRR_MASK) {
+			unsigned int k;
+
+			writel(readl(&mmc_base->stat) | BRR_MASK,
+				&mmc_base->stat);
+			for (k = 0; k < count; k++) {
+				*output_buf = readl(&mmc_base->data);
+				output_buf++;
+			}
+			size -= (count*4);
+		}
+
+		if (mmc_stat & BWR_MASK)
+			writel(readl(&mmc_base->stat) | BWR_MASK,
+				&mmc_base->stat);
+
+		if (mmc_stat & TC_MASK) {
+			writel(readl(&mmc_base->stat) | TC_MASK,
+				&mmc_base->stat);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
+				unsigned int size)
+{
+	unsigned int *input_buf = (unsigned int *)buf;
+	unsigned int mmc_stat;
+	unsigned int count;
+
+	/*
+	 * Start Polled Write
+	 */
+	count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+	count /= 4;
+
+	while (size) {
+		ulong start = get_timer(0);
+		do {
+			mmc_stat = readl(&mmc_base->stat);
+			if (get_timer(0) - start > MAX_RETRY_MS) {
+				printf("%s: timedout waiting for status!\n",
+						__func__);
+				return TIMEOUT;
+			}
+		} while (mmc_stat == 0);
+
+		if ((mmc_stat & (IE_DTO | IE_DCRC | IE_DEB)) != 0)
+			mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
+
+		if ((mmc_stat & ERRI_MASK) != 0)
+			return 1;
+
+		if (mmc_stat & BWR_MASK) {
+			unsigned int k;
+
+			writel(readl(&mmc_base->stat) | BWR_MASK,
+					&mmc_base->stat);
+			for (k = 0; k < count; k++) {
+				writel(*input_buf, &mmc_base->data);
+				input_buf++;
+			}
+			size -= (count*4);
+		}
+
+		if (mmc_stat & BRR_MASK)
+			writel(readl(&mmc_base->stat) | BRR_MASK,
+				&mmc_base->stat);
+
+		if (mmc_stat & TC_MASK) {
+			writel(readl(&mmc_base->stat) | TC_MASK,
+				&mmc_base->stat);
+			break;
+		}
+	}
+	return 0;
+}
+
+static void mmc_set_ios(struct mmc *mmc)
+{
+	struct hsmmc *mmc_base;
+	unsigned int dsor = 0;
+	ulong start;
+
+	mmc_base = ((struct omap_hsmmc_data *)mmc->priv)->base_addr;
+	/* configue bus width */
+	switch (mmc->bus_width) {
+	case 8:
+		writel(readl(&mmc_base->con) | DTW_8_BITMODE,
+			&mmc_base->con);
+		break;
+
+	case 4:
+		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+			&mmc_base->con);
+		writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
+			&mmc_base->hctl);
+		break;
+
+	case 1:
+	default:
+		writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+			&mmc_base->con);
+		writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
+			&mmc_base->hctl);
+		break;
+	}
+
+	/* configure clock with 96Mhz system clock.
+	 */
+	if (mmc->clock != 0) {
+		dsor = (MMC_CLOCK_REFERENCE * 1000000 / mmc->clock);
+		if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > mmc->clock)
+			dsor++;
+	}
+
+	mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+				(ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+
+	mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+				(dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+	start = get_timer(0);
+	while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+		if (get_timer(0) - start > MAX_RETRY_MS) {
+			printf("%s: timedout waiting for ics!\n", __func__);
+			return;
+		}
+	}
+	writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+}
+
+int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
+		int wp_gpio)
+{
+	struct mmc *mmc = &hsmmc_dev[dev_index];
+	struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];
+	uint host_caps_val = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
+			     MMC_MODE_HC;
+
+	sprintf(mmc->name, "OMAP SD/MMC");
+	mmc->send_cmd = mmc_send_cmd;
+	mmc->set_ios = mmc_set_ios;
+	mmc->init = mmc_init_setup;
+	mmc->priv = priv_data;
+
+	switch (dev_index) {
+	case 0:
+		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
+		break;
+#ifdef OMAP_HSMMC2_BASE
+	case 1:
+		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
+#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
+     defined(CONFIG_DRA7XX)) && defined(CONFIG_HSMMC2_8BIT)
+		/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
+		host_caps_val |= MMC_MODE_8BIT;
+#endif
+		break;
+#endif
+#ifdef OMAP_HSMMC3_BASE
+	case 2:
+		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
+#if defined(CONFIG_DRA7XX) && defined(CONFIG_HSMMC3_8BIT)
+		/* Enable 8-bit interface for eMMC on DRA7XX */
+		host_caps_val |= MMC_MODE_8BIT;
+#endif
+		break;
+#endif
+	default:
+		priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
+		return 1;
+	}
+	priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
+	if (priv_data->cd_gpio != -1)
+		mmc->getcd = omap_mmc_getcd;
+
+	priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
+	if (priv_data->wp_gpio != -1)
+		mmc->getwp = omap_mmc_getwp;
+
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+	mmc->host_caps = host_caps_val & ~host_caps_mask;
+
+	mmc->f_min = 400000;
+
+	if (f_max != 0)
+		mmc->f_max = f_max;
+	else {
+		if (mmc->host_caps & MMC_MODE_HS) {
+			if (mmc->host_caps & MMC_MODE_HS_52MHz)
+				mmc->f_max = 52000000;
+			else
+				mmc->f_max = 26000000;
+		} else
+			mmc->f_max = 20000000;
+	}
+
+	mmc->b_max = 0;
+
+#if defined(CONFIG_OMAP34XX)
+	/*
+	 * Silicon revs 2.1 and older do not support multiblock transfers.
+	 */
+	if ((get_cpu_family() == CPU_OMAP34XX) && (get_cpu_rev() <= CPU_3XX_ES21))
+		mmc->b_max = 1;
+#endif
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/pxa_mmc.h b/marvell/uboot/drivers/mmc/pxa_mmc.h
new file mode 100644
index 0000000..6fa4268
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/pxa_mmc.h
@@ -0,0 +1,138 @@
+/*
+ *  linux/drivers/mmc/mmc_pxa.h
+ *
+ *  Author: Vladimir Shebordaev, Igor Oblakov
+ *  Copyright:  MontaVista Software Inc.
+ *
+ *  $Id: mmc_pxa.h,v 0.3.1.6 2002/09/25 19:25:48 ted Exp ted $
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#ifndef __MMC_PXA_P_H__
+#define __MMC_PXA_P_H__
+
+/* PXA-250 MMC controller registers */
+
+/* MMC_STRPCL */
+#define MMC_STRPCL_STOP_CLK		(0x0001UL)
+#define MMC_STRPCL_START_CLK		(0x0002UL)
+
+/* MMC_STAT */
+#define MMC_STAT_END_CMD_RES		(0x0001UL << 13)
+#define MMC_STAT_PRG_DONE		(0x0001UL << 12)
+#define MMC_STAT_DATA_TRAN_DONE		(0x0001UL << 11)
+#define MMC_STAT_CLK_EN			(0x0001UL << 8)
+#define MMC_STAT_RECV_FIFO_FULL		(0x0001UL << 7)
+#define MMC_STAT_XMIT_FIFO_EMPTY	(0x0001UL << 6)
+#define MMC_STAT_RES_CRC_ERROR		(0x0001UL << 5)
+#define MMC_STAT_SPI_READ_ERROR_TOKEN   (0x0001UL << 4)
+#define MMC_STAT_CRC_READ_ERROR		(0x0001UL << 3)
+#define MMC_STAT_CRC_WRITE_ERROR	(0x0001UL << 2)
+#define MMC_STAT_TIME_OUT_RESPONSE	(0x0001UL << 1)
+#define MMC_STAT_READ_TIME_OUT		(0x0001UL)
+
+#define MMC_STAT_ERRORS (MMC_STAT_RES_CRC_ERROR|MMC_STAT_SPI_READ_ERROR_TOKEN\
+	|MMC_STAT_CRC_READ_ERROR|MMC_STAT_TIME_OUT_RESPONSE\
+	|MMC_STAT_READ_TIME_OUT|MMC_STAT_CRC_WRITE_ERROR)
+
+/* MMC_CLKRT */
+#define MMC_CLKRT_20MHZ			(0x0000UL)
+#define MMC_CLKRT_10MHZ			(0x0001UL)
+#define MMC_CLKRT_5MHZ			(0x0002UL)
+#define MMC_CLKRT_2_5MHZ		(0x0003UL)
+#define MMC_CLKRT_1_25MHZ		(0x0004UL)
+#define MMC_CLKRT_0_625MHZ		(0x0005UL)
+#define MMC_CLKRT_0_3125MHZ		(0x0006UL)
+
+/* MMC_SPI */
+#define MMC_SPI_DISABLE			(0x00UL)
+#define MMC_SPI_EN			(0x01UL)
+#define MMC_SPI_CS_EN			(0x01UL << 2)
+#define MMC_SPI_CS_ADDRESS		(0x01UL << 3)
+#define MMC_SPI_CRC_ON			(0x01UL << 1)
+
+/* MMC_CMDAT */
+#define MMC_CMDAT_SD_4DAT		(0x0001UL << 8)
+#define MMC_CMDAT_MMC_DMA_EN		(0x0001UL << 7)
+#define MMC_CMDAT_INIT			(0x0001UL << 6)
+#define MMC_CMDAT_BUSY			(0x0001UL << 5)
+#define MMC_CMDAT_BCR			(0x0003UL << 5)
+#define MMC_CMDAT_STREAM		(0x0001UL << 4)
+#define MMC_CMDAT_BLOCK			(0x0000UL << 4)
+#define MMC_CMDAT_WRITE			(0x0001UL << 3)
+#define MMC_CMDAT_READ			(0x0000UL << 3)
+#define MMC_CMDAT_DATA_EN		(0x0001UL << 2)
+#define MMC_CMDAT_R0			(0)
+#define MMC_CMDAT_R1			(0x0001UL)
+#define MMC_CMDAT_R2			(0x0002UL)
+#define MMC_CMDAT_R3			(0x0003UL)
+
+/* MMC_RESTO */
+#define MMC_RES_TO_MAX			(0x007fUL) /* [6:0] */
+
+/* MMC_RDTO */
+#define MMC_READ_TO_MAX			(0x0ffffUL) /* [15:0] */
+
+/* MMC_BLKLEN */
+#define MMC_BLK_LEN_MAX			(0x03ffUL) /* [9:0] */
+
+/* MMC_PRTBUF */
+#define MMC_PRTBUF_BUF_PART_FULL	(0x01UL)
+#define MMC_PRTBUF_BUF_FULL		(0x00UL    )
+
+/* MMC_I_MASK */
+#define MMC_I_MASK_TXFIFO_WR_REQ	(0x01UL << 6)
+#define MMC_I_MASK_RXFIFO_RD_REQ	(0x01UL << 5)
+#define MMC_I_MASK_CLK_IS_OFF		(0x01UL << 4)
+#define MMC_I_MASK_STOP_CMD		(0x01UL << 3)
+#define MMC_I_MASK_END_CMD_RES		(0x01UL << 2)
+#define MMC_I_MASK_PRG_DONE		(0x01UL << 1)
+#define MMC_I_MASK_DATA_TRAN_DONE       (0x01UL)
+#define MMC_I_MASK_ALL			(0x07fUL)
+
+
+/* MMC_I_REG */
+#define MMC_I_REG_TXFIFO_WR_REQ		(0x01UL << 6)
+#define MMC_I_REG_RXFIFO_RD_REQ		(0x01UL << 5)
+#define MMC_I_REG_CLK_IS_OFF		(0x01UL << 4)
+#define MMC_I_REG_STOP_CMD		(0x01UL << 3)
+#define MMC_I_REG_END_CMD_RES		(0x01UL << 2)
+#define MMC_I_REG_PRG_DONE		(0x01UL << 1)
+#define MMC_I_REG_DATA_TRAN_DONE	(0x01UL)
+#define MMC_I_REG_ALL			(0x007fUL)
+
+/* MMC_CMD */
+#define MMC_CMD_INDEX_MAX		(0x006fUL)  /* [5:0] */
+#define CMD(x)  (x)
+
+#define MMC_DEFAULT_RCA			1
+
+#define MMC_BLOCK_SIZE			512
+#define MMC_MAX_BLOCK_SIZE		512
+
+#define MMC_R1_IDLE_STATE		0x01
+#define MMC_R1_ERASE_STATE		0x02
+#define MMC_R1_ILLEGAL_CMD		0x04
+#define MMC_R1_COM_CRC_ERR		0x08
+#define MMC_R1_ERASE_SEQ_ERR		0x01
+#define MMC_R1_ADDR_ERR			0x02
+#define MMC_R1_PARAM_ERR		0x04
+
+#define MMC_R1B_WP_ERASE_SKIP		0x0002
+#define MMC_R1B_ERR			0x0004
+#define MMC_R1B_CC_ERR			0x0008
+#define MMC_R1B_CARD_ECC_ERR		0x0010
+#define MMC_R1B_WP_VIOLATION		0x0020
+#define MMC_R1B_ERASE_PARAM		0x0040
+#define MMC_R1B_OOR			0x0080
+#define MMC_R1B_IDLE_STATE		0x0100
+#define MMC_R1B_ERASE_RESET		0x0200
+#define MMC_R1B_ILLEGAL_CMD		0x0400
+#define MMC_R1B_COM_CRC_ERR		0x0800
+#define MMC_R1B_ERASE_SEQ_ERR		0x1000
+#define MMC_R1B_ADDR_ERR		0x2000
+#define MMC_R1B_PARAM_ERR		0x4000
+
+#endif /* __MMC_PXA_P_H__ */
diff --git a/marvell/uboot/drivers/mmc/pxa_mmc_gen.c b/marvell/uboot/drivers/mmc/pxa_mmc_gen.c
new file mode 100644
index 0000000..29f3eaf
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/pxa_mmc_gen.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Loosely based on the old code and Linux's PXA MMC driver
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-mmc.h>
+#include <asm/io.h>
+
+/* PXAMMC Generic default config for various CPUs */
+#if defined(CONFIG_CPU_PXA25X)
+#define PXAMMC_FIFO_SIZE	1
+#define PXAMMC_MIN_SPEED	312500
+#define PXAMMC_MAX_SPEED	20000000
+#define PXAMMC_HOST_CAPS	(0)
+#elif defined(CONFIG_CPU_PXA27X)
+#define PXAMMC_CRC_SKIP
+#define PXAMMC_FIFO_SIZE	32
+#define PXAMMC_MIN_SPEED	304000
+#define PXAMMC_MAX_SPEED	19500000
+#define PXAMMC_HOST_CAPS	(MMC_MODE_4BIT)
+#elif defined(CONFIG_CPU_MONAHANS)
+#define PXAMMC_FIFO_SIZE	32
+#define PXAMMC_MIN_SPEED	304000
+#define PXAMMC_MAX_SPEED	26000000
+#define PXAMMC_HOST_CAPS	(MMC_MODE_4BIT | MMC_MODE_HS)
+#else
+#error "This CPU isn't supported by PXA MMC!"
+#endif
+
+#define MMC_STAT_ERRORS							\
+	(MMC_STAT_RES_CRC_ERROR | MMC_STAT_SPI_READ_ERROR_TOKEN |	\
+	MMC_STAT_CRC_READ_ERROR | MMC_STAT_TIME_OUT_RESPONSE |		\
+	MMC_STAT_READ_TIME_OUT | MMC_STAT_CRC_WRITE_ERROR)
+
+/* 1 millisecond (in wait cycles below it's 100 x 10uS waits) */
+#define PXA_MMC_TIMEOUT	100
+
+struct pxa_mmc_priv {
+	struct pxa_mmc_regs *regs;
+};
+
+/* Wait for bit to be set */
+static int pxa_mmc_wait(struct mmc *mmc, uint32_t mask)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	unsigned int timeout = PXA_MMC_TIMEOUT;
+
+	/* Wait for bit to be set */
+	while (--timeout) {
+		if (readl(&regs->stat) & mask)
+			break;
+		udelay(10);
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int pxa_mmc_stop_clock(struct mmc *mmc)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	unsigned int timeout = PXA_MMC_TIMEOUT;
+
+	/* If the clock aren't running, exit */
+	if (!(readl(&regs->stat) & MMC_STAT_CLK_EN))
+		return 0;
+
+	/* Tell the controller to turn off the clock */
+	writel(MMC_STRPCL_STOP_CLK, &regs->strpcl);
+
+	/* Wait until the clock are off */
+	while (--timeout) {
+		if (!(readl(&regs->stat) & MMC_STAT_CLK_EN))
+			break;
+		udelay(10);
+	}
+
+	/* The clock refused to stop, scream and die a painful death */
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	/* The clock stopped correctly */
+	return 0;
+}
+
+static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+				uint32_t cmdat)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	int ret;
+
+	/* The card can send a "busy" response */
+	if (cmd->resp_type & MMC_RSP_BUSY)
+		cmdat |= MMC_CMDAT_BUSY;
+
+	/* Inform the controller about response type */
+	switch (cmd->resp_type) {
+	case MMC_RSP_R1:
+	case MMC_RSP_R1b:
+		cmdat |= MMC_CMDAT_R1;
+		break;
+	case MMC_RSP_R2:
+		cmdat |= MMC_CMDAT_R2;
+		break;
+	case MMC_RSP_R3:
+		cmdat |= MMC_CMDAT_R3;
+		break;
+	default:
+		break;
+	}
+
+	/* Load command and it's arguments into the controller */
+	writel(cmd->cmdidx, &regs->cmd);
+	writel(cmd->cmdarg >> 16, &regs->argh);
+	writel(cmd->cmdarg & 0xffff, &regs->argl);
+	writel(cmdat, &regs->cmdat);
+
+	/* Start the controller clock and wait until they are started */
+	writel(MMC_STRPCL_START_CLK, &regs->strpcl);
+
+	ret = pxa_mmc_wait(mmc, MMC_STAT_CLK_EN);
+	if (ret)
+		return ret;
+
+	/* Correct and happy end */
+	return 0;
+}
+
+static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	uint32_t a, b, c;
+	int i;
+	int stat;
+
+	/* Read the controller status */
+	stat = readl(&regs->stat);
+
+	/*
+	 * 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(&regs->res) & 0xffff;
+	for (i = 0; i < 4; i++) {
+		b = readl(&regs->res) & 0xffff;
+		c = readl(&regs->res) & 0xffff;
+		cmd->response[i] = (a << 24) | (b << 8) | (c >> 8);
+		a = c;
+	}
+
+	/* The command response didn't arrive */
+	if (stat & MMC_STAT_TIME_OUT_RESPONSE)
+		return -ETIMEDOUT;
+	else if (stat & MMC_STAT_RES_CRC_ERROR
+			&& cmd->resp_type & MMC_RSP_CRC) {
+#ifdef	PXAMMC_CRC_SKIP
+		if (cmd->resp_type & MMC_RSP_136
+				&& cmd->response[0] & (1 << 31))
+			printf("Ignoring CRC, this may be dangerous!\n");
+		else
+#endif
+		return -EILSEQ;
+	}
+
+	/* The command response was successfully read */
+	return 0;
+}
+
+static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	uint32_t len;
+	uint32_t *buf = (uint32_t *)data->dest;
+	int size;
+	int ret;
+
+	len = data->blocks * data->blocksize;
+
+	while (len) {
+		/* The controller has data ready */
+		if (readl(&regs->i_reg) & MMC_I_REG_RXFIFO_RD_REQ) {
+			size = min(len, PXAMMC_FIFO_SIZE);
+			len -= size;
+			size /= 4;
+
+			/* Read data into the buffer */
+			while (size--)
+				*buf++ = readl(&regs->rxfifo);
+
+		}
+
+		if (readl(&regs->stat) & MMC_STAT_ERRORS)
+			return -EIO;
+	}
+
+	/* Wait for the transmission-done interrupt */
+	ret = pxa_mmc_wait(mmc, MMC_STAT_DATA_TRAN_DONE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	uint32_t len;
+	uint32_t *buf = (uint32_t *)data->src;
+	int size;
+	int ret;
+
+	len = data->blocks * data->blocksize;
+
+	while (len) {
+		/* The controller is ready to receive data */
+		if (readl(&regs->i_reg) & MMC_I_REG_TXFIFO_WR_REQ) {
+			size = min(len, PXAMMC_FIFO_SIZE);
+			len -= size;
+			size /= 4;
+
+			while (size--)
+				writel(*buf++, &regs->txfifo);
+
+			if (min(len, PXAMMC_FIFO_SIZE) < 32)
+				writel(MMC_PRTBUF_BUF_PART_FULL, &regs->prtbuf);
+		}
+
+		if (readl(&regs->stat) & MMC_STAT_ERRORS)
+			return -EIO;
+	}
+
+	/* Wait for the transmission-done interrupt */
+	ret = pxa_mmc_wait(mmc, MMC_STAT_DATA_TRAN_DONE);
+	if (ret)
+		return ret;
+
+	/* Wait until the data are really written to the card */
+	ret = pxa_mmc_wait(mmc, MMC_STAT_PRG_DONE);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int pxa_mmc_request(struct mmc *mmc, struct mmc_cmd *cmd,
+				struct mmc_data *data)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	uint32_t cmdat = 0;
+	int ret;
+
+	/* Stop the controller */
+	ret = pxa_mmc_stop_clock(mmc);
+	if (ret)
+		return ret;
+
+	/* If we're doing data transfer, configure the controller accordingly */
+	if (data) {
+		writel(data->blocks, &regs->nob);
+		writel(data->blocksize, &regs->blklen);
+		/* This delay can be optimized, but stick with max value */
+		writel(0xffff, &regs->rdto);
+		cmdat |= MMC_CMDAT_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			cmdat |= MMC_CMDAT_WRITE;
+	}
+
+	/* Run in 4bit mode if the card can do it */
+	if (mmc->bus_width == 4)
+		cmdat |= MMC_CMDAT_SD_4DAT;
+
+	/* Execute the command */
+	ret = pxa_mmc_start_cmd(mmc, cmd, cmdat);
+	if (ret)
+		return ret;
+
+	/* Wait until the command completes */
+	ret = pxa_mmc_wait(mmc, MMC_STAT_END_CMD_RES);
+	if (ret)
+		return ret;
+
+	/* Read back the result */
+	ret = pxa_mmc_cmd_done(mmc, cmd);
+	if (ret)
+		return ret;
+
+	/* In case there was a data transfer scheduled, do it */
+	if (data) {
+		if (data->flags & MMC_DATA_WRITE)
+			pxa_mmc_do_write_xfer(mmc, data);
+		else
+			pxa_mmc_do_read_xfer(mmc, data);
+	}
+
+	return 0;
+}
+
+static void pxa_mmc_set_ios(struct mmc *mmc)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+	uint32_t tmp;
+	uint32_t pxa_mmc_clock;
+
+	if (!mmc->clock) {
+		pxa_mmc_stop_clock(mmc);
+		return;
+	}
+
+	/* PXA3xx can do 26MHz with special settings. */
+	if (mmc->clock == 26000000) {
+		writel(0x7, &regs->clkrt);
+		return;
+	}
+
+	/* Set clock to the card the usual way. */
+	pxa_mmc_clock = 0;
+	tmp = mmc->f_max / mmc->clock;
+	tmp += tmp % 2;
+
+	while (tmp > 1) {
+		pxa_mmc_clock++;
+		tmp >>= 1;
+	}
+
+	writel(pxa_mmc_clock, &regs->clkrt);
+}
+
+static int pxa_mmc_init(struct mmc *mmc)
+{
+	struct pxa_mmc_priv *priv = (struct pxa_mmc_priv *)mmc->priv;
+	struct pxa_mmc_regs *regs = priv->regs;
+
+	/* Make sure the clock are stopped */
+	pxa_mmc_stop_clock(mmc);
+
+	/* Turn off SPI mode */
+	writel(0, &regs->spi);
+
+	/* Set up maximum timeout to wait for command response */
+	writel(MMC_RES_TO_MAX_MASK, &regs->resto);
+
+	/* Mask all interrupts */
+	writel(~(MMC_I_MASK_TXFIFO_WR_REQ | MMC_I_MASK_RXFIFO_RD_REQ),
+		&regs->i_mask);
+	return 0;
+}
+
+int pxa_mmc_register(int card_index)
+{
+	struct mmc *mmc;
+	struct pxa_mmc_priv *priv;
+	uint32_t reg;
+	int ret = -ENOMEM;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		goto err0;
+
+	priv = malloc(sizeof(struct pxa_mmc_priv));
+	if (!priv)
+		goto err1;
+
+	switch (card_index) {
+	case 0:
+		priv->regs = (struct pxa_mmc_regs *)MMC0_BASE;
+		break;
+	case 1:
+		priv->regs = (struct pxa_mmc_regs *)MMC1_BASE;
+		break;
+	default:
+		printf("PXA MMC: Invalid MMC controller ID (card_index = %d)\n",
+			card_index);
+		goto err2;
+	}
+
+	mmc->priv = priv;
+
+	sprintf(mmc->name, "PXA MMC");
+	mmc->send_cmd	= pxa_mmc_request;
+	mmc->set_ios	= pxa_mmc_set_ios;
+	mmc->init	= pxa_mmc_init;
+	mmc->getcd	= NULL;
+
+	mmc->voltages	= MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max	= PXAMMC_MAX_SPEED;
+	mmc->f_min	= PXAMMC_MIN_SPEED;
+	mmc->host_caps	= PXAMMC_HOST_CAPS;
+
+	mmc->b_max = 0;
+
+#ifndef	CONFIG_CPU_MONAHANS	/* PXA2xx */
+	reg = readl(CKEN);
+	reg |= CKEN12_MMC;
+	writel(reg, CKEN);
+#else				/* PXA3xx */
+	reg = readl(CKENA);
+	reg |= CKENA_12_MMC0 | CKENA_13_MMC1;
+	writel(reg, CKENA);
+#endif
+
+	mmc_register(mmc);
+
+	return 0;
+
+err2:
+	free(priv);
+err1:
+	free(mmc);
+err0:
+	return ret;
+}
diff --git a/marvell/uboot/drivers/mmc/s5p_sdhci.c b/marvell/uboot/drivers/mmc/s5p_sdhci.c
new file mode 100644
index 0000000..40ff873
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/s5p_sdhci.c
@@ -0,0 +1,88 @@
+/*
+ * (C) Copyright 2012 SAMSUNG Electronics
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/clk.h>
+
+static char *S5P_NAME = "SAMSUNG SDHCI";
+static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
+{
+	unsigned long val, ctrl;
+	/*
+	 * SELCLKPADDS[17:16]
+	 * 00 = 2mA
+	 * 01 = 4mA
+	 * 10 = 7mA
+	 * 11 = 9mA
+	 */
+	sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4);
+
+	val = sdhci_readl(host, SDHCI_CONTROL2);
+	val &= SDHCI_CTRL2_SELBASECLK_SHIFT;
+
+	val |=	SDHCI_CTRL2_ENSTAASYNCCLR |
+		SDHCI_CTRL2_ENCMDCNFMSK |
+		SDHCI_CTRL2_ENFBCLKRX |
+		SDHCI_CTRL2_ENCLKOUTHOLD;
+
+	sdhci_writel(host, val, SDHCI_CONTROL2);
+
+	/*
+	 * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7]
+	 * FCSel[1:0] : Rx Feedback Clock Delay Control
+	 *	Inverter delay means10ns delay if SDCLK 50MHz setting
+	 *	01 = Delay1 (basic delay)
+	 *	11 = Delay2 (basic delay + 2ns)
+	 *	00 = Delay3 (inverter delay)
+	 *	10 = Delay4 (inverter delay + 2ns)
+	 */
+	val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1;
+	sdhci_writel(host, val, SDHCI_CONTROL3);
+
+	/*
+	 * SELBASECLK[5:4]
+	 * 00/01 = HCLK
+	 * 10 = EPLL
+	 * 11 = XTI or XEXTCLK
+	 */
+	ctrl = sdhci_readl(host, SDHCI_CONTROL2);
+	ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3);
+	ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2);
+	sdhci_writel(host, ctrl, SDHCI_CONTROL2);
+}
+
+int s5p_sdhci_init(u32 regbase, int index, int bus_width)
+{
+	struct sdhci_host *host = NULL;
+	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+	if (!host) {
+		printf("sdhci__host malloc fail!\n");
+		return 1;
+	}
+
+	host->name = S5P_NAME;
+	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_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8;
+	host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+	host->set_control_reg = &s5p_sdhci_set_control_reg;
+	host->set_clock = set_mmc_clk;
+	host->index = index;
+
+	host->host_caps = MMC_MODE_HC;
+	if (bus_width == 8)
+		host->host_caps |= MMC_MODE_8BIT;
+
+	return add_sdhci(host, 52000000, 400000);
+}
diff --git a/marvell/uboot/drivers/mmc/sdhci.c b/marvell/uboot/drivers/mmc/sdhci.c
new file mode 100644
index 0000000..5911a53
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/sdhci.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright 2011, Marvell Semiconductor Inc.
+ * Lei Wen <leiwen@marvell.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Back ported to the 8xx platform (from the 8260 platform) by
+ * Murray.Jensen@cmst.csiro.au, 27-Jan-01.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <sdhci.h>
+
+void *aligned_buffer;
+
+static void sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	unsigned long timeout;
+
+	/* Wait max 100 ms */
+	timeout = 100;
+	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
+		if (timeout == 0) {
+			printf("%s: Reset 0x%x never completed.\n",
+			       __func__, (int)mask);
+			return;
+		}
+		timeout--;
+		udelay(1000);
+	}
+}
+
+static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd)
+{
+	int i;
+	if (cmd->resp_type & MMC_RSP_136) {
+		/* CRC is stripped so we need to do some shifting. */
+		for (i = 0; i < 4; i++) {
+			cmd->response[i] = sdhci_readl(host,
+					SDHCI_RESPONSE + (3-i)*4) << 8;
+			if (i != 3)
+				cmd->response[i] |= sdhci_readb(host,
+						SDHCI_RESPONSE + (3-i)*4-1);
+		}
+	} else {
+		cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE);
+	}
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
+{
+	int i;
+	char *offs;
+	for (i = 0; i < data->blocksize; i += 4) {
+		offs = data->dest + i;
+		if (data->flags == MMC_DATA_READ)
+			*(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER);
+		else
+			sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER);
+	}
+}
+
+static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
+				unsigned int start_addr)
+{
+	unsigned int stat, rdy, mask, block = 0;
+#ifdef CONFIG_MMC_SDMA
+	unsigned char ctrl;
+	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+	ctrl &= ~SDHCI_CTRL_DMA_MASK;
+	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+#endif
+
+	rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
+	mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
+	do {
+		stat = sdhci_readl(host, SDHCI_INT_STATUS);
+		if (stat & SDHCI_INT_ERROR) {
+			printf("%s: Error detected in status(0x%X)!\n",
+			       __func__, stat);
+			return -1;
+		}
+		if (stat & rdy) {
+			if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask))
+				continue;
+			sdhci_writel(host, rdy, SDHCI_INT_STATUS);
+			sdhci_transfer_pio(host, data);
+			data->dest += data->blocksize;
+			if (++block >= data->blocks)
+				break;
+		}
+#ifdef CONFIG_MMC_SDMA
+		if (stat & SDHCI_INT_DMA_END) {
+			sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
+			start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
+			start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
+			sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
+		}
+#endif
+		udelay(10);
+	} while (!(stat & SDHCI_INT_DATA_END));
+	return 0;
+}
+
+/*
+ * No command will be sent by driver if card is busy, so driver must wait
+ * for card ready state.
+ * Every time when card is busy after timeout then (last) timeout value will be
+ * increased twice but only if it doesn't exceed global defined maximum.
+ * Each function call will use last timeout value. Max timeout can be redefined
+ * in board config file.
+ */
+#ifndef CONFIG_SDHCI_CMD_MAX_TIMEOUT
+#define CONFIG_SDHCI_CMD_MAX_TIMEOUT		3200
+#endif
+#define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT	100
+
+int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
+		       struct mmc_data *data)
+{
+	struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
+	unsigned int stat = 0;
+	int ret = 0;
+	int trans_bytes = 0, is_aligned = 1;
+	u32 mask, flags, mode;
+	unsigned int time = 0, start_addr = 0, timeout_loop = 10;
+	int mmc_dev = mmc->block_dev.dev;
+
+	/* Timeout unit - ms */
+	static unsigned int cmd_timeout = CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT;
+
+	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
+	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
+
+	/* We shouldn't wait for data inihibit for stop commands, even
+	   though they might use busy signaling */
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		mask &= ~SDHCI_DATA_INHIBIT;
+
+	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
+		if (time >= cmd_timeout) {
+			printf("%s: MMC: %d busy ", __func__, mmc_dev);
+			if (2 * cmd_timeout <= CONFIG_SDHCI_CMD_MAX_TIMEOUT) {
+				cmd_timeout += cmd_timeout;
+				printf("timeout increasing to: %u ms.\n",
+				       cmd_timeout);
+			} else {
+				puts("timeout.\n");
+				return COMM_ERR;
+			}
+		}
+		time++;
+		udelay(1000);
+	}
+
+	mask = SDHCI_INT_RESPONSE;
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->resp_type & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->resp_type & MMC_RSP_BUSY) {
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+		mask |= SDHCI_INT_DATA_END;
+	} else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+	if (data)
+		flags |= SDHCI_CMD_DATA;
+
+	/* Set Transfer mode regarding to data flag */
+	if (data != 0) {
+		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
+		mode = SDHCI_TRNS_BLK_CNT_EN;
+		trans_bytes = data->blocks * data->blocksize;
+		if (data->blocks > 1)
+			mode |= SDHCI_TRNS_MULTI;
+
+		if (data->flags == MMC_DATA_READ)
+			mode |= SDHCI_TRNS_READ;
+
+#ifdef CONFIG_MMC_SDMA
+		if (data->flags == MMC_DATA_READ)
+			start_addr = (unsigned int)data->dest;
+		else
+			start_addr = (unsigned int)data->src;
+		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+				(start_addr & 0x7) != 0x0) {
+			is_aligned = 0;
+			start_addr = (unsigned int)aligned_buffer;
+			if (data->flags != MMC_DATA_READ)
+				memcpy(aligned_buffer, data->src, trans_bytes);
+		}
+
+		sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
+		mode |= SDHCI_TRNS_DMA;
+#endif
+		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+				data->blocksize),
+				SDHCI_BLOCK_SIZE);
+		sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
+		sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
+	} else if (cmd->resp_type & MMC_RSP_BUSY) {
+		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
+	}
+
+	sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
+#ifdef CONFIG_MMC_SDMA
+	flush_cache(start_addr, trans_bytes);
+#endif
+	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
+
+	do {
+		stat = sdhci_readl(host, SDHCI_INT_STATUS);
+		if (stat & SDHCI_INT_ERROR) {
+			if (!(stat & SDHCI_INT_DATA_TIMEOUT)) {
+				break;
+			} else if (timeout_loop--) {
+				sdhci_writel(host, SDHCI_INT_DATA_TIMEOUT,
+						SDHCI_INT_STATUS);
+				continue;
+			}
+		}
+	} while ((stat & mask) != mask);
+
+	if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
+		sdhci_cmd_done(host, cmd);
+		sdhci_writel(host, mask, SDHCI_INT_STATUS);
+	} else
+		ret = -1;
+
+	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) {
+		if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+				!is_aligned && (data->flags == MMC_DATA_READ))
+			memcpy(data->dest, aligned_buffer, trans_bytes);
+		return 0;
+	}
+
+	sdhci_reset(host, SDHCI_RESET_CMD);
+	sdhci_reset(host, SDHCI_RESET_DATA);
+	if (stat & SDHCI_INT_TIMEOUT)
+		return TIMEOUT;
+	else
+		return COMM_ERR;
+}
+
+static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
+{
+	struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
+	unsigned int div, clk, timeout;
+
+	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+	if (clock == 0)
+		return 0;
+
+	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+		/* Version 3.00 divisors must be a multiple of 2. */
+		if (mmc->f_max <= clock)
+			div = 1;
+		else {
+			for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
+				if ((mmc->f_max / div) <= clock)
+					break;
+			}
+		}
+	} else {
+		/* Version 2.00 divisors must be a power of 2. */
+		for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+			if ((mmc->f_max / div) <= clock)
+				break;
+		}
+	}
+	div >>= 1;
+
+	if (host->set_clock)
+		host->set_clock(host->index, div);
+
+	clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+	clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+		<< SDHCI_DIVIDER_HI_SHIFT;
+	clk |= SDHCI_CLOCK_INT_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+	/* Wait max 20 ms */
+	timeout = 20;
+	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+		& SDHCI_CLOCK_INT_STABLE)) {
+		if (timeout == 0) {
+			printf("%s: Internal clock never stabilised.\n",
+			       __func__);
+			return -1;
+		}
+		timeout--;
+		udelay(1000);
+	}
+
+	clk |= SDHCI_CLOCK_CARD_EN;
+	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+	return 0;
+}
+
+static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+{
+	u8 pwr = 0;
+
+	if (power != (unsigned short)-1) {
+		switch (1 << power) {
+		case MMC_VDD_165_195:
+			pwr = SDHCI_POWER_180;
+			break;
+		case MMC_VDD_29_30:
+		case MMC_VDD_30_31:
+			pwr = SDHCI_POWER_300;
+			break;
+		case MMC_VDD_32_33:
+		case MMC_VDD_33_34:
+			pwr = SDHCI_POWER_330;
+			break;
+		}
+	}
+
+	if (pwr == 0) {
+		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+		return;
+	}
+
+	if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+	pwr |= SDHCI_POWER_ON;
+
+	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+}
+
+#ifdef CONFIG_SDHCI_PXAV3
+#define MAX_WAIT_COUNT 74
+void sdhci_set_74_clk(struct mmc *mmc)
+{
+	struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
+	u16 tmp = 0;
+	int count = 0;
+
+	tmp = sdhci_readw(host, SD_CE_ATA_2);
+	tmp |= SDCE_MISC_INT | SDCE_MISC_INT_EN;
+	sdhci_writew(host, tmp, SD_CE_ATA_2);
+
+	tmp = sdhci_readl(host, SD_CFG_FIFO_PARAM);
+	tmp |= SDCFG_GEN_PAD_CLK_ON;
+	sdhci_writel(host, tmp, SD_CFG_FIFO_PARAM);
+
+	while (count++ < MAX_WAIT_COUNT + 1) {
+		if (sdhci_readw(host, SD_CE_ATA_2) & SDCE_MISC_INT)
+			break;
+		udelay(1000000/mmc->clock + 1);
+	}
+	if (count > MAX_WAIT_COUNT + 1)
+		printf("%s[%d]: 74 clk done(no wait) %d\n",
+		       host->name, mmc->block_dev.dev, --count);
+}
+#else
+void sdhci_set_74_clk(struct mmc *mmc) {}
+#endif
+
+void sdhci_set_ios(struct mmc *mmc)
+{
+	u32 ctrl;
+	struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
+
+	if (host->set_control_reg)
+		host->set_control_reg(host);
+
+	if (mmc->clock != host->clock)
+		sdhci_set_clock(mmc, mmc->clock);
+
+	/* Set bus width */
+	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+	if (mmc->bus_width == 8) {
+		ctrl &= ~SDHCI_CTRL_4BITBUS;
+		if ((SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) ||
+				(host->quirks & SDHCI_QUIRK_USE_WIDE8))
+			ctrl |= SDHCI_CTRL_8BITBUS;
+	} else {
+		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
+			ctrl &= ~SDHCI_CTRL_8BITBUS;
+		if (mmc->bus_width == 4)
+			ctrl |= SDHCI_CTRL_4BITBUS;
+		else
+			ctrl &= ~SDHCI_CTRL_4BITBUS;
+	}
+
+	if (mmc->clock > 26000000)
+		ctrl |= SDHCI_CTRL_HISPD;
+	else
+		ctrl &= ~SDHCI_CTRL_HISPD;
+
+	if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)
+		ctrl &= ~SDHCI_CTRL_HISPD;
+
+	sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+
+int sdhci_init(struct mmc *mmc)
+{
+	struct sdhci_host *host = (struct sdhci_host *)mmc->priv;
+
+	if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) {
+		aligned_buffer = memalign(8, 512*1024);
+		if (!aligned_buffer) {
+			printf("%s: Aligned buffer alloc failed!!!\n",
+			       __func__);
+			return -1;
+		}
+	}
+
+	sdhci_set_power(host, fls(mmc->voltages) - 1);
+
+	if (host->quirks & SDHCI_QUIRK_NO_CD) {
+		unsigned int status;
+
+		sdhci_writel(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
+			SDHCI_HOST_CONTROL);
+
+		status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+		while ((!(status & SDHCI_CARD_PRESENT)) ||
+		    (!(status & SDHCI_CARD_STATE_STABLE)) ||
+		    (!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
+			status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+	}
+
+	/* Enable only interrupts served by the SD controller */
+	sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK,
+		     SDHCI_INT_ENABLE);
+	/* Mask all sdhci interrupt sources */
+	sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE);
+
+	return 0;
+}
+
+int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
+{
+	struct mmc *mmc;
+	unsigned int caps;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc) {
+		printf("%s: mmc malloc fail!\n", __func__);
+		return -1;
+	}
+	memset(mmc, 0, sizeof(struct mmc));
+
+	mmc->priv = host;
+	host->mmc = mmc;
+
+	sprintf(mmc->name, "%s", host->name);
+	mmc->send_cmd = sdhci_send_command;
+	mmc->set_ios = sdhci_set_ios;
+	mmc->set_74_clk = sdhci_set_74_clk;
+	mmc->init = sdhci_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+
+	caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+#ifdef CONFIG_MMC_SDMA
+	if (!(caps & SDHCI_CAN_DO_SDMA)) {
+		printf("%s: Your controller doesn't support SDMA!!\n",
+		       __func__);
+		return -1;
+	}
+#endif
+
+	if (max_clk)
+		mmc->f_max = max_clk;
+	else {
+		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
+			mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+				>> SDHCI_CLOCK_BASE_SHIFT;
+		else
+			mmc->f_max = (caps & SDHCI_CLOCK_BASE_MASK)
+				>> SDHCI_CLOCK_BASE_SHIFT;
+		mmc->f_max *= 1000000;
+	}
+	if (mmc->f_max == 0) {
+		printf("%s: Hardware doesn't specify base clock frequency\n",
+		       __func__);
+		return -1;
+	}
+	if (min_clk)
+		mmc->f_min = min_clk;
+	else {
+		if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
+			mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300;
+		else
+			mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200;
+	}
+
+	mmc->voltages = 0;
+	if (caps & SDHCI_CAN_VDD_330)
+		mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+	if (caps & SDHCI_CAN_VDD_300)
+		mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+	if (caps & SDHCI_CAN_VDD_180)
+		mmc->voltages |= MMC_VDD_165_195;
+
+	if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE)
+		mmc->voltages |= host->voltages;
+
+	mmc->host_caps = MMC_MODE_HC | MMC_MODE_HS | MMC_MODE_HS_52MHz |
+			 MMC_MODE_4BIT;
+	if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+		if (caps & SDHCI_CAN_DO_8BIT)
+			mmc->host_caps |= MMC_MODE_8BIT;
+	}
+	if (host->host_caps)
+		mmc->host_caps |= host->host_caps;
+
+	sdhci_reset(host, SDHCI_RESET_ALL);
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/sh_mmcif.c b/marvell/uboot/drivers/mmc/sh_mmcif.c
new file mode 100644
index 0000000..011d4f3
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/sh_mmcif.c
@@ -0,0 +1,610 @@
+/*
+ * MMCIF driver.
+ *
+ * Copyright (C)  2011 Renesas Solutions Corp.
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <mmc.h>
+#include <malloc.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include "sh_mmcif.h"
+
+#define DRIVER_NAME	"sh_mmcif"
+
+static void *mmc_priv(struct mmc *mmc)
+{
+	return (void *)mmc->priv;
+}
+
+static int sh_mmcif_intr(void *dev_id)
+{
+	struct sh_mmcif_host *host = dev_id;
+	u32 state = 0;
+
+	state = sh_mmcif_read(&host->regs->ce_int);
+	state &= sh_mmcif_read(&host->regs->ce_int_mask);
+
+	if (state & INT_RBSYE) {
+		sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_CRSPE) {
+		sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask);
+		/* one more interrupt (INT_RBSYE) */
+		if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY)
+			return -EAGAIN;
+		goto end;
+	} else if (state & INT_BUFREN) {
+		sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_BUFWEN) {
+		sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_CMD12DRE) {
+		sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE |
+				  INT_BUFRE), &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_BUFRE) {
+		sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_DTRANE) {
+		sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_CMD12RBE) {
+		sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE),
+				&host->regs->ce_int);
+		sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask);
+		goto end;
+	} else if (state & INT_ERR_STS) {
+		/* err interrupts */
+		sh_mmcif_write(~state, &host->regs->ce_int);
+		sh_mmcif_bitclr(state, &host->regs->ce_int_mask);
+		goto err;
+	} else
+		return -EAGAIN;
+
+err:
+	host->sd_error = 1;
+	debug("%s: int err state = %08x\n", DRIVER_NAME, state);
+end:
+	host->wait_int = 1;
+	return 0;
+}
+
+static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host)
+{
+	int timeout = 10000000;
+
+	while (1) {
+		timeout--;
+		if (timeout < 0) {
+			printf("timeout\n");
+			return 0;
+		}
+
+		if (!sh_mmcif_intr(host))
+			break;
+
+		udelay(1);	/* 1 usec */
+	}
+
+	return 1;	/* Return value: NOT 0 = complete waiting */
+}
+
+static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
+{
+	int i;
+
+	sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl);
+	sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl);
+
+	if (!clk)
+		return;
+	if (clk == CLKDEV_EMMC_DATA) {
+		sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl);
+	} else {
+		for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++)
+			;
+		sh_mmcif_bitset((i - 1) << 16, &host->regs->ce_clk_ctrl);
+	}
+	sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl);
+}
+
+static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
+{
+	u32 tmp;
+
+	tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE |
+							 CLK_CLEAR);
+
+	sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version);
+	sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version);
+	sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29,
+			&host->regs->ce_clk_ctrl);
+	/* byte swap on */
+	sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc);
+}
+
+static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
+{
+	u32 state1, state2;
+	int ret, timeout = 10000000;
+
+	host->sd_error = 0;
+	host->wait_int = 0;
+
+	state1 = sh_mmcif_read(&host->regs->ce_host_sts1);
+	state2 = sh_mmcif_read(&host->regs->ce_host_sts2);
+	debug("%s: ERR HOST_STS1 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1));
+	debug("%s: ERR HOST_STS2 = %08x\n", \
+			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2));
+
+	if (state1 & STS1_CMDSEQ) {
+		debug("%s: Forced end of command sequence\n", DRIVER_NAME);
+		sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
+		sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
+		while (1) {
+			timeout--;
+			if (timeout < 0) {
+				printf(DRIVER_NAME": Forceed end of " \
+					"command sequence timeout err\n");
+				return -EILSEQ;
+			}
+			if (!(sh_mmcif_read(&host->regs->ce_host_sts1)
+								& STS1_CMDSEQ))
+				break;
+		}
+		sh_mmcif_sync_reset(host);
+		return -EILSEQ;
+	}
+
+	if (state2 & STS2_CRC_ERR)
+		ret = -EILSEQ;
+	else if (state2 & STS2_TIMEOUT_ERR)
+		ret = TIMEOUT;
+	else
+		ret = -EILSEQ;
+	return ret;
+}
+
+static int sh_mmcif_single_read(struct sh_mmcif_host *host,
+				struct mmc_data *data)
+{
+	long time;
+	u32 blocksize, i;
+	unsigned long *p = (unsigned long *)data->dest;
+
+	if ((unsigned long)p & 0x00000001) {
+		printf("%s: The data pointer is unaligned.", __func__);
+		return -EIO;
+	}
+
+	host->wait_int = 0;
+
+	/* buf read enable */
+	sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
+	time = mmcif_wait_interrupt_flag(host);
+	if (time == 0 || host->sd_error != 0)
+		return sh_mmcif_error_manage(host);
+
+	host->wait_int = 0;
+	blocksize = (BLOCK_SIZE_MASK &
+			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
+	for (i = 0; i < blocksize / 4; i++)
+		*p++ = sh_mmcif_read(&host->regs->ce_data);
+
+	/* buffer read end */
+	sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask);
+	time = mmcif_wait_interrupt_flag(host);
+	if (time == 0 || host->sd_error != 0)
+		return sh_mmcif_error_manage(host);
+
+	host->wait_int = 0;
+	return 0;
+}
+
+static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
+				struct mmc_data *data)
+{
+	long time;
+	u32 blocksize, i, j;
+	unsigned long *p = (unsigned long *)data->dest;
+
+	if ((unsigned long)p & 0x00000001) {
+		printf("%s: The data pointer is unaligned.", __func__);
+		return -EIO;
+	}
+
+	host->wait_int = 0;
+	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
+	for (j = 0; j < data->blocks; j++) {
+		sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
+		time = mmcif_wait_interrupt_flag(host);
+		if (time == 0 || host->sd_error != 0)
+			return sh_mmcif_error_manage(host);
+
+		host->wait_int = 0;
+		for (i = 0; i < blocksize / 4; i++)
+			*p++ = sh_mmcif_read(&host->regs->ce_data);
+
+		WATCHDOG_RESET();
+	}
+	return 0;
+}
+
+static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+				 struct mmc_data *data)
+{
+	long time;
+	u32 blocksize, i;
+	const unsigned long *p = (unsigned long *)data->dest;
+
+	if ((unsigned long)p & 0x00000001) {
+		printf("%s: The data pointer is unaligned.", __func__);
+		return -EIO;
+	}
+
+	host->wait_int = 0;
+	sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
+
+	time = mmcif_wait_interrupt_flag(host);
+	if (time == 0 || host->sd_error != 0)
+		return sh_mmcif_error_manage(host);
+
+	host->wait_int = 0;
+	blocksize = (BLOCK_SIZE_MASK &
+			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
+	for (i = 0; i < blocksize / 4; i++)
+		sh_mmcif_write(*p++, &host->regs->ce_data);
+
+	/* buffer write end */
+	sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask);
+
+	time = mmcif_wait_interrupt_flag(host);
+	if (time == 0 || host->sd_error != 0)
+		return sh_mmcif_error_manage(host);
+
+	host->wait_int = 0;
+	return 0;
+}
+
+static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
+				struct mmc_data *data)
+{
+	long time;
+	u32 i, j, blocksize;
+	const unsigned long *p = (unsigned long *)data->dest;
+
+	if ((unsigned long)p & 0x00000001) {
+		printf("%s: The data pointer is unaligned.", __func__);
+		return -EIO;
+	}
+
+	host->wait_int = 0;
+	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
+	for (j = 0; j < data->blocks; j++) {
+		sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
+
+		time = mmcif_wait_interrupt_flag(host);
+
+		if (time == 0 || host->sd_error != 0)
+			return sh_mmcif_error_manage(host);
+
+		host->wait_int = 0;
+		for (i = 0; i < blocksize / 4; i++)
+			sh_mmcif_write(*p++, &host->regs->ce_data);
+
+		WATCHDOG_RESET();
+	}
+	return 0;
+}
+
+static void sh_mmcif_get_response(struct sh_mmcif_host *host,
+					struct mmc_cmd *cmd)
+{
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3);
+		cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2);
+		cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1);
+		cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0);
+		debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0],
+			 cmd->response[1], cmd->response[2], cmd->response[3]);
+	} else {
+		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0);
+	}
+}
+
+static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
+					struct mmc_cmd *cmd)
+{
+	cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12);
+}
+
+static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
+				struct mmc_data *data, struct mmc_cmd *cmd)
+{
+	u32 tmp = 0;
+	u32 opc = cmd->cmdidx;
+
+	/* Response Type check */
+	switch (cmd->resp_type) {
+	case MMC_RSP_NONE:
+		tmp |= CMD_SET_RTYP_NO;
+		break;
+	case MMC_RSP_R1:
+	case MMC_RSP_R1b:
+	case MMC_RSP_R3:
+		tmp |= CMD_SET_RTYP_6B;
+		break;
+	case MMC_RSP_R2:
+		tmp |= CMD_SET_RTYP_17B;
+		break;
+	default:
+		printf(DRIVER_NAME": Not support type response.\n");
+		break;
+	}
+
+	/* RBSY */
+	if (opc == MMC_CMD_SWITCH)
+		tmp |= CMD_SET_RBSY;
+
+	/* WDAT / DATW */
+	if (host->data) {
+		tmp |= CMD_SET_WDAT;
+		switch (host->bus_width) {
+		case MMC_BUS_WIDTH_1:
+			tmp |= CMD_SET_DATW_1;
+			break;
+		case MMC_BUS_WIDTH_4:
+			tmp |= CMD_SET_DATW_4;
+			break;
+		case MMC_BUS_WIDTH_8:
+			tmp |= CMD_SET_DATW_8;
+			break;
+		default:
+			printf(DRIVER_NAME": Not support bus width.\n");
+			break;
+		}
+	}
+	/* DWEN */
+	if (opc == MMC_CMD_WRITE_SINGLE_BLOCK ||
+	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK)
+		tmp |= CMD_SET_DWEN;
+	/* CMLTE/CMD12EN */
+	if (opc == MMC_CMD_READ_MULTIPLE_BLOCK ||
+	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
+		tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
+		sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set);
+	}
+	/* RIDXC[1:0] check bits */
+	if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID ||
+	    opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
+		tmp |= CMD_SET_RIDXC_BITS;
+	/* RCRC7C[1:0] check bits */
+	if (opc == MMC_CMD_SEND_OP_COND)
+		tmp |= CMD_SET_CRC7C_BITS;
+	/* RCRC7C[1:0] internal CRC7 */
+	if (opc == MMC_CMD_ALL_SEND_CID ||
+		opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
+		tmp |= CMD_SET_CRC7C_INTERNAL;
+
+	return opc = ((opc << 24) | tmp);
+}
+
+static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
+				struct mmc_data *data, u16 opc)
+{
+	u32 ret;
+
+	switch (opc) {
+	case MMC_CMD_READ_MULTIPLE_BLOCK:
+		ret = sh_mmcif_multi_read(host, data);
+		break;
+	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+		ret = sh_mmcif_multi_write(host, data);
+		break;
+	case MMC_CMD_WRITE_SINGLE_BLOCK:
+		ret = sh_mmcif_single_write(host, data);
+		break;
+	case MMC_CMD_READ_SINGLE_BLOCK:
+	case MMC_CMD_SEND_EXT_CSD:
+		ret = sh_mmcif_single_read(host, data);
+		break;
+	default:
+		printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
+				struct mmc_data *data, struct mmc_cmd *cmd)
+{
+	long time;
+	int ret = 0, mask = 0;
+	u32 opc = cmd->cmdidx;
+
+	if (opc == MMC_CMD_STOP_TRANSMISSION) {
+		/* MMCIF sends the STOP command automatically */
+		if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK)
+			sh_mmcif_bitset(MASK_MCMD12DRE,
+					&host->regs->ce_int_mask);
+		else
+			sh_mmcif_bitset(MASK_MCMD12RBE,
+					&host->regs->ce_int_mask);
+
+		time = mmcif_wait_interrupt_flag(host);
+		if (time == 0 || host->sd_error != 0)
+			return sh_mmcif_error_manage(host);
+
+		sh_mmcif_get_cmd12response(host, cmd);
+		return 0;
+	}
+	if (opc == MMC_CMD_SWITCH)
+		mask = MASK_MRBSYE;
+	else
+		mask = MASK_MCRSPE;
+
+	mask |=	MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
+		MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
+		MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
+		MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
+
+	if (host->data) {
+		sh_mmcif_write(0, &host->regs->ce_block_set);
+		sh_mmcif_write(data->blocksize, &host->regs->ce_block_set);
+	}
+	opc = sh_mmcif_set_cmd(host, data, cmd);
+
+	sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int);
+	sh_mmcif_write(mask, &host->regs->ce_int_mask);
+
+	debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg);
+	/* set arg */
+	sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg);
+	host->wait_int = 0;
+	/* set cmd */
+	sh_mmcif_write(opc, &host->regs->ce_cmd_set);
+
+	time = mmcif_wait_interrupt_flag(host);
+	if (time == 0)
+		return sh_mmcif_error_manage(host);
+
+	if (host->sd_error) {
+		switch (cmd->cmdidx) {
+		case MMC_CMD_ALL_SEND_CID:
+		case MMC_CMD_SELECT_CARD:
+		case MMC_CMD_APP_CMD:
+			ret = TIMEOUT;
+			break;
+		default:
+			printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx);
+			ret = sh_mmcif_error_manage(host);
+			break;
+		}
+		host->sd_error = 0;
+		host->wait_int = 0;
+		return ret;
+	}
+
+	/* if no response */
+	if (!(opc & 0x00C00000))
+		return 0;
+
+	if (host->wait_int == 1) {
+		sh_mmcif_get_response(host, cmd);
+		host->wait_int = 0;
+	}
+	if (host->data)
+		ret = sh_mmcif_data_trans(host, data, cmd->cmdidx);
+	host->last_cmd = cmd->cmdidx;
+
+	return ret;
+}
+
+static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd,
+			    struct mmc_data *data)
+{
+	struct sh_mmcif_host *host = mmc_priv(mmc);
+	int ret;
+
+	WATCHDOG_RESET();
+
+	switch (cmd->cmdidx) {
+	case MMC_CMD_APP_CMD:
+		return TIMEOUT;
+	case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
+		if (data)
+			/* ext_csd */
+			break;
+		else
+			/* send_if_cond cmd (not support) */
+			return TIMEOUT;
+	default:
+		break;
+	}
+	host->sd_error = 0;
+	host->data = data;
+	ret = sh_mmcif_start_cmd(host, data, cmd);
+	host->data = NULL;
+
+	return ret;
+}
+
+static void sh_mmcif_set_ios(struct mmc *mmc)
+{
+	struct sh_mmcif_host *host = mmc_priv(mmc);
+
+	if (mmc->clock)
+		sh_mmcif_clock_control(host, mmc->clock);
+
+	if (mmc->bus_width == 8)
+		host->bus_width = MMC_BUS_WIDTH_8;
+	else if (mmc->bus_width == 4)
+		host->bus_width = MMC_BUS_WIDTH_4;
+	else
+		host->bus_width = MMC_BUS_WIDTH_1;
+
+	debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
+}
+
+static int sh_mmcif_init(struct mmc *mmc)
+{
+	struct sh_mmcif_host *host = mmc_priv(mmc);
+
+	sh_mmcif_sync_reset(host);
+	sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask);
+	return 0;
+}
+
+int mmcif_mmc_init(void)
+{
+	int ret = 0;
+	struct mmc *mmc;
+	struct sh_mmcif_host *host = NULL;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		ret = -ENOMEM;
+	memset(mmc, 0, sizeof(*mmc));
+	host = malloc(sizeof(struct sh_mmcif_host));
+	if (!host)
+		ret = -ENOMEM;
+	memset(host, 0, sizeof(*host));
+
+	mmc->f_min = CLKDEV_MMC_INIT;
+	mmc->f_max = CLKDEV_EMMC_DATA;
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
+			 MMC_MODE_8BIT | MMC_MODE_HC;
+	memcpy(mmc->name, DRIVER_NAME, sizeof(DRIVER_NAME));
+	mmc->send_cmd = sh_mmcif_request;
+	mmc->set_ios = sh_mmcif_set_ios;
+	mmc->init = sh_mmcif_init;
+	mmc->getcd = NULL;
+	mmc->getwp = NULL;
+	host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
+	host->clk = CONFIG_SH_MMCIF_CLK;
+	mmc->priv = host;
+
+	mmc_register(mmc);
+
+	return ret;
+}
diff --git a/marvell/uboot/drivers/mmc/sh_mmcif.h b/marvell/uboot/drivers/mmc/sh_mmcif.h
new file mode 100644
index 0000000..bd6fbf7
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/sh_mmcif.h
@@ -0,0 +1,238 @@
+/*
+ * MMCIF driver.
+ *
+ * Copyright (C)  2011 Renesas Solutions Corp.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _SH_MMCIF_H_
+#define _SH_MMCIF_H_
+
+struct sh_mmcif_regs {
+	unsigned long ce_cmd_set;
+	unsigned long reserved;
+	unsigned long ce_arg;
+	unsigned long ce_arg_cmd12;
+	unsigned long ce_cmd_ctrl;
+	unsigned long ce_block_set;
+	unsigned long ce_clk_ctrl;
+	unsigned long ce_buf_acc;
+	unsigned long ce_resp3;
+	unsigned long ce_resp2;
+	unsigned long ce_resp1;
+	unsigned long ce_resp0;
+	unsigned long ce_resp_cmd12;
+	unsigned long ce_data;
+	unsigned long reserved2[2];
+	unsigned long ce_int;
+	unsigned long ce_int_mask;
+	unsigned long ce_host_sts1;
+	unsigned long ce_host_sts2;
+	unsigned long reserved3[11];
+	unsigned long ce_version;
+};
+
+/* CE_CMD_SET */
+#define CMD_MASK		0x3f000000
+#define CMD_SET_RTYP_NO		((0 << 23) | (0 << 22))
+/* R1/R1b/R3/R4/R5 */
+#define CMD_SET_RTYP_6B		((0 << 23) | (1 << 22))
+/* R2 */
+#define CMD_SET_RTYP_17B	((1 << 23) | (0 << 22))
+/* R1b */
+#define CMD_SET_RBSY		(1 << 21)
+#define CMD_SET_CCSEN		(1 << 20)
+/* 1: on data, 0: no data */
+#define CMD_SET_WDAT		(1 << 19)
+/* 1: write to card, 0: read from card */
+#define CMD_SET_DWEN		(1 << 18)
+/* 1: multi block trans, 0: single */
+#define CMD_SET_CMLTE		(1 << 17)
+/* 1: CMD12 auto issue */
+#define CMD_SET_CMD12EN		(1 << 16)
+/* index check */
+#define CMD_SET_RIDXC_INDEX	((0 << 15) | (0 << 14))
+/* check bits check */
+#define CMD_SET_RIDXC_BITS	((0 << 15) | (1 << 14))
+/* no check */
+#define CMD_SET_RIDXC_NO	((1 << 15) | (0 << 14))
+/* 1: CRC7 check*/
+#define CMD_SET_CRC7C		((0 << 13) | (0 << 12))
+/* 1: check bits check*/
+#define CMD_SET_CRC7C_BITS	((0 << 13) | (1 << 12))
+/* 1: internal CRC7 check*/
+#define CMD_SET_CRC7C_INTERNAL	((1 << 13) | (0 << 12))
+/* 1: CRC16 check*/
+#define CMD_SET_CRC16C		(1 << 10)
+/* 1: not receive CRC status */
+#define CMD_SET_CRCSTE		(1 << 8)
+/* 1: tran mission bit "Low" */
+#define CMD_SET_TBIT		(1 << 7)
+/* 1: open/drain */
+#define CMD_SET_OPDM		(1 << 6)
+#define CMD_SET_CCSH		(1 << 5)
+/* 1bit */
+#define CMD_SET_DATW_1		((0 << 1) | (0 << 0))
+/* 4bit */
+#define CMD_SET_DATW_4		((0 << 1) | (1 << 0))
+/* 8bit */
+#define CMD_SET_DATW_8		((1 << 1) | (0 << 0))
+
+/* CE_CMD_CTRL */
+#define CMD_CTRL_BREAK		(1 << 0)
+
+/* CE_BLOCK_SET */
+#define BLOCK_SIZE_MASK		0x0000ffff
+
+/* CE_CLK_CTRL */
+#define CLK_ENABLE		(1 << 24)
+#define CLK_CLEAR		((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+#define CLK_PCLK		((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+/* respons timeout */
+#define SRSPTO_256		((1 << 13) | (0 << 12))
+/* respons busy timeout */
+#define SRBSYTO_29		((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8))
+/* read/write timeout */
+#define SRWDTO_29		((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4))
+/* ccs timeout */
+#define SCCSTO_29		((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
+
+/* CE_BUF_ACC */
+#define BUF_ACC_DMAWEN		(1 << 25)
+#define BUF_ACC_DMAREN		(1 << 24)
+#define BUF_ACC_BUSW_32		(0 << 17)
+#define BUF_ACC_BUSW_16		(1 << 17)
+#define BUF_ACC_ATYP		(1 << 16)
+
+/* CE_INT */
+#define INT_CCSDE		(1 << 29)
+#define INT_CMD12DRE		(1 << 26)
+#define INT_CMD12RBE		(1 << 25)
+#define INT_CMD12CRE		(1 << 24)
+#define INT_DTRANE		(1 << 23)
+#define INT_BUFRE		(1 << 22)
+#define INT_BUFWEN		(1 << 21)
+#define INT_BUFREN		(1 << 20)
+#define INT_CCSRCV		(1 << 19)
+#define INT_RBSYE		(1 << 17)
+#define INT_CRSPE		(1 << 16)
+#define INT_CMDVIO		(1 << 15)
+#define INT_BUFVIO		(1 << 14)
+#define INT_WDATERR		(1 << 11)
+#define INT_RDATERR		(1 << 10)
+#define INT_RIDXERR		(1 << 9)
+#define INT_RSPERR		(1 << 8)
+#define INT_CCSTO		(1 << 5)
+#define INT_CRCSTO		(1 << 4)
+#define INT_WDATTO		(1 << 3)
+#define INT_RDATTO		(1 << 2)
+#define INT_RBSYTO		(1 << 1)
+#define INT_RSPTO		(1 << 0)
+#define INT_ERR_STS		(INT_CMDVIO | INT_BUFVIO | INT_WDATERR |  \
+				 INT_RDATERR | INT_RIDXERR | INT_RSPERR | \
+				 INT_CCSTO | INT_CRCSTO | INT_WDATTO |	  \
+				 INT_RDATTO | INT_RBSYTO | INT_RSPTO)
+#define INT_START_MAGIC		0xD80430C0
+
+/* CE_INT_MASK */
+#define MASK_ALL		0x00000000
+#define MASK_MCCSDE		(1 << 29)
+#define MASK_MCMD12DRE		(1 << 26)
+#define MASK_MCMD12RBE		(1 << 25)
+#define MASK_MCMD12CRE		(1 << 24)
+#define MASK_MDTRANE		(1 << 23)
+#define MASK_MBUFRE		(1 << 22)
+#define MASK_MBUFWEN		(1 << 21)
+#define MASK_MBUFREN		(1 << 20)
+#define MASK_MCCSRCV		(1 << 19)
+#define MASK_MRBSYE		(1 << 17)
+#define MASK_MCRSPE		(1 << 16)
+#define MASK_MCMDVIO		(1 << 15)
+#define MASK_MBUFVIO		(1 << 14)
+#define MASK_MWDATERR		(1 << 11)
+#define MASK_MRDATERR		(1 << 10)
+#define MASK_MRIDXERR		(1 << 9)
+#define MASK_MRSPERR		(1 << 8)
+#define MASK_MCCSTO		(1 << 5)
+#define MASK_MCRCSTO		(1 << 4)
+#define MASK_MWDATTO		(1 << 3)
+#define MASK_MRDATTO		(1 << 2)
+#define MASK_MRBSYTO		(1 << 1)
+#define MASK_MRSPTO		(1 << 0)
+
+/* CE_HOST_STS1 */
+#define STS1_CMDSEQ		(1 << 31)
+
+/* CE_HOST_STS2 */
+#define STS2_CRCSTE		(1 << 31)
+#define STS2_CRC16E		(1 << 30)
+#define STS2_AC12CRCE		(1 << 29)
+#define STS2_RSPCRC7E		(1 << 28)
+#define STS2_CRCSTEBE		(1 << 27)
+#define STS2_RDATEBE		(1 << 26)
+#define STS2_AC12REBE		(1 << 25)
+#define STS2_RSPEBE		(1 << 24)
+#define STS2_AC12IDXE		(1 << 23)
+#define STS2_RSPIDXE		(1 << 22)
+#define STS2_CCSTO		(1 << 15)
+#define STS2_RDATTO		(1 << 14)
+#define STS2_DATBSYTO		(1 << 13)
+#define STS2_CRCSTTO		(1 << 12)
+#define STS2_AC12BSYTO		(1 << 11)
+#define STS2_RSPBSYTO		(1 << 10)
+#define STS2_AC12RSPTO		(1 << 9)
+#define STS2_RSPTO		(1 << 8)
+
+#define STS2_CRC_ERR		(STS2_CRCSTE | STS2_CRC16E |		\
+				 STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE)
+#define STS2_TIMEOUT_ERR	(STS2_CCSTO | STS2_RDATTO |		\
+				 STS2_DATBSYTO | STS2_CRCSTTO |		\
+				 STS2_AC12BSYTO | STS2_RSPBSYTO |	\
+				 STS2_AC12RSPTO | STS2_RSPTO)
+
+/* CE_VERSION */
+#define SOFT_RST_ON		(1 << 31)
+#define SOFT_RST_OFF		(0 << 31)
+
+#define CLKDEV_EMMC_DATA	52000000	/* 52MHz */
+#define	CLKDEV_MMC_INIT		400000		/* 100 - 400 KHz */
+
+#define MMC_BUS_WIDTH_1		0
+#define MMC_BUS_WIDTH_4		2
+#define MMC_BUS_WIDTH_8		3
+
+struct sh_mmcif_host {
+	struct mmc_data		*data;
+	struct sh_mmcif_regs	*regs;
+	unsigned int		clk;
+	int			bus_width;
+	u16			wait_int;
+	u16			sd_error;
+	u8			last_cmd;
+};
+
+static inline u32 sh_mmcif_read(unsigned long *reg)
+{
+	return readl(reg);
+}
+
+static inline void sh_mmcif_write(u32 val, unsigned long *reg)
+{
+	writel(val, reg);
+}
+
+static inline void sh_mmcif_bitset(u32 val, unsigned long *reg)
+{
+	sh_mmcif_write(val | sh_mmcif_read(reg), reg);
+}
+
+static inline void sh_mmcif_bitclr(u32 val, unsigned long *reg)
+{
+	sh_mmcif_write(~val & sh_mmcif_read(reg), reg);
+}
+
+#endif /* _SH_MMCIF_H_ */
diff --git a/marvell/uboot/drivers/mmc/socfpga_dw_mmc.c b/marvell/uboot/drivers/mmc/socfpga_dw_mmc.c
new file mode 100644
index 0000000..bc53a5d
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/socfpga_dw_mmc.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013 Altera Corporation <www.altera.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <dwmmc.h>
+#include <asm/arch/dwmmc.h>
+#include <asm/arch/clock_manager.h>
+#include <asm/arch/system_manager.h>
+
+static const struct socfpga_clock_manager *clock_manager_base =
+		(void *)SOCFPGA_CLKMGR_ADDRESS;
+static const struct socfpga_system_manager *system_manager_base =
+		(void *)SOCFPGA_SYSMGR_ADDRESS;
+
+static char *SOCFPGA_NAME = "SOCFPGA DWMMC";
+
+static void socfpga_dwmci_clksel(struct dwmci_host *host)
+{
+	unsigned int drvsel;
+	unsigned int smplsel;
+
+	/* Disable SDMMC clock. */
+	clrbits_le32(&clock_manager_base->per_pll_en,
+		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+
+	/* Configures drv_sel and smpl_sel */
+	drvsel = CONFIG_SOCFPGA_DWMMC_DRVSEL;
+	smplsel = CONFIG_SOCFPGA_DWMMC_SMPSEL;
+
+	debug("%s: drvsel %d smplsel %d\n", __func__, drvsel, smplsel);
+	writel(SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel),
+		&system_manager_base->sdmmcgrp_ctrl);
+
+	debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
+		readl(&system_manager_base->sdmmcgrp_ctrl));
+
+	/* Enable SDMMC clock */
+	setbits_le32(&clock_manager_base->per_pll_en,
+		CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+}
+
+int socfpga_dwmmc_init(u32 regbase, int bus_width, int index)
+{
+	struct dwmci_host *host = NULL;
+	host = calloc(sizeof(struct dwmci_host), 1);
+	if (!host) {
+		printf("dwmci_host calloc fail!\n");
+		return -1;
+	}
+
+	host->name = SOCFPGA_NAME;
+	host->ioaddr = (void *)regbase;
+	host->buswidth = bus_width;
+	host->clksel = socfpga_dwmci_clksel;
+	host->dev_index = index;
+	/* fixed clock divide by 4 which due to the SDMMC wrapper */
+	host->bus_hz = CONFIG_SOCFPGA_DWMMC_BUS_HZ;
+	host->fifoth_val = MSIZE(0x2) |
+		RX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2 - 1) |
+		TX_WMARK(CONFIG_SOCFPGA_DWMMC_FIFO_DEPTH / 2);
+
+	return add_dwmci(host, host->bus_hz, 400000);
+}
+
diff --git a/marvell/uboot/drivers/mmc/spear_sdhci.c b/marvell/uboot/drivers/mmc/spear_sdhci.c
new file mode 100644
index 0000000..6ca96a2
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/spear_sdhci.c
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+
+int spear_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
+{
+	struct sdhci_host *host = NULL;
+	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+	if (!host) {
+		printf("sdhci host malloc fail!\n");
+		return 1;
+	}
+
+	host->name = "sdhci";
+	host->ioaddr = (void *)regbase;
+	host->quirks = quirks;
+
+	if (quirks & SDHCI_QUIRK_REG32_RW)
+		host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+	else
+		host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+	add_sdhci(host, max_clk, min_clk);
+	return 0;
+}
diff --git a/marvell/uboot/drivers/mmc/tegra_mmc.c b/marvell/uboot/drivers/mmc/tegra_mmc.c
new file mode 100644
index 0000000..e1817e2
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/tegra_mmc.c
@@ -0,0 +1,688 @@
+/*
+ * (C) Copyright 2009 SAMSUNG Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ * Portions Copyright 2011-2013 NVIDIA Corporation
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <bouncebuf.h>
+#include <common.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/tegra_mmc.h>
+#include <mmc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct mmc mmc_dev[MAX_HOSTS];
+struct mmc_host mmc_host[MAX_HOSTS];
+
+#ifndef CONFIG_OF_CONTROL
+#error "Please enable device tree support to use this driver"
+#endif
+
+static void mmc_set_power(struct mmc_host *host, unsigned short power)
+{
+	u8 pwr = 0;
+	debug("%s: power = %x\n", __func__, power);
+
+	if (power != (unsigned short)-1) {
+		switch (1 << power) {
+		case MMC_VDD_165_195:
+			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
+			break;
+		case MMC_VDD_29_30:
+		case MMC_VDD_30_31:
+			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_0;
+			break;
+		case MMC_VDD_32_33:
+		case MMC_VDD_33_34:
+			pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
+			break;
+		}
+	}
+	debug("%s: pwr = %X\n", __func__, pwr);
+
+	/* Set the bus voltage first (if any) */
+	writeb(pwr, &host->reg->pwrcon);
+	if (pwr == 0)
+		return;
+
+	/* Now enable bus power */
+	pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
+	writeb(pwr, &host->reg->pwrcon);
+}
+
+static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data,
+				struct bounce_buffer *bbstate)
+{
+	unsigned char ctrl;
+
+
+	debug("buf: %p (%p), data->blocks: %u, data->blocksize: %u\n",
+		bbstate->bounce_buffer, bbstate->user_buffer, data->blocks,
+		data->blocksize);
+
+	writel((u32)bbstate->bounce_buffer, &host->reg->sysad);
+	/*
+	 * DMASEL[4:3]
+	 * 00 = Selects SDMA
+	 * 01 = Reserved
+	 * 10 = Selects 32-bit Address ADMA2
+	 * 11 = Selects 64-bit Address ADMA2
+	 */
+	ctrl = readb(&host->reg->hostctl);
+	ctrl &= ~TEGRA_MMC_HOSTCTL_DMASEL_MASK;
+	ctrl |= TEGRA_MMC_HOSTCTL_DMASEL_SDMA;
+	writeb(ctrl, &host->reg->hostctl);
+
+	/* We do not handle DMA boundaries, so set it to max (512 KiB) */
+	writew((7 << 12) | (data->blocksize & 0xFFF), &host->reg->blksize);
+	writew(data->blocks, &host->reg->blkcnt);
+}
+
+static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data)
+{
+	unsigned short mode;
+	debug(" mmc_set_transfer_mode called\n");
+	/*
+	 * TRNMOD
+	 * MUL1SIN0[5]	: Multi/Single Block Select
+	 * RD1WT0[4]	: Data Transfer Direction Select
+	 *	1 = read
+	 *	0 = write
+	 * ENACMD12[2]	: Auto CMD12 Enable
+	 * ENBLKCNT[1]	: Block Count Enable
+	 * ENDMA[0]	: DMA Enable
+	 */
+	mode = (TEGRA_MMC_TRNMOD_DMA_ENABLE |
+		TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE);
+
+	if (data->blocks > 1)
+		mode |= TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT;
+
+	if (data->flags & MMC_DATA_READ)
+		mode |= TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ;
+
+	writew(mode, &host->reg->trnmod);
+}
+
+static int mmc_wait_inhibit(struct mmc_host *host,
+			    struct mmc_cmd *cmd,
+			    struct mmc_data *data,
+			    unsigned int timeout)
+{
+	/*
+	 * PRNSTS
+	 * CMDINHDAT[1] : Command Inhibit (DAT)
+	 * CMDINHCMD[0] : Command Inhibit (CMD)
+	 */
+	unsigned int mask = TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD;
+
+	/*
+	 * We shouldn't wait for data inhibit for stop commands, even
+	 * though they might use busy signaling
+	 */
+	if ((data == NULL) && (cmd->resp_type & MMC_RSP_BUSY))
+		mask |= TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT;
+
+	while (readl(&host->reg->prnsts) & mask) {
+		if (timeout == 0) {
+			printf("%s: timeout error\n", __func__);
+			return -1;
+		}
+		timeout--;
+		udelay(1000);
+	}
+
+	return 0;
+}
+
+static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data, struct bounce_buffer *bbstate)
+{
+	struct mmc_host *host = (struct mmc_host *)mmc->priv;
+	int flags, i;
+	int result;
+	unsigned int mask = 0;
+	unsigned int retry = 0x100000;
+	debug(" mmc_send_cmd called\n");
+
+	result = mmc_wait_inhibit(host, cmd, data, 10 /* ms */);
+
+	if (result < 0)
+		return result;
+
+	if (data)
+		mmc_prepare_data(host, data, bbstate);
+
+	debug("cmd->arg: %08x\n", cmd->cmdarg);
+	writel(cmd->cmdarg, &host->reg->argument);
+
+	if (data)
+		mmc_set_transfer_mode(host, data);
+
+	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
+		return -1;
+
+	/*
+	 * CMDREG
+	 * CMDIDX[13:8]	: Command index
+	 * DATAPRNT[5]	: Data Present Select
+	 * ENCMDIDX[4]	: Command Index Check Enable
+	 * ENCMDCRC[3]	: Command CRC Check Enable
+	 * RSPTYP[1:0]
+	 *	00 = No Response
+	 *	01 = Length 136
+	 *	10 = Length 48
+	 *	11 = Length 48 Check busy after response
+	 */
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE;
+	else if (cmd->resp_type & MMC_RSP_136)
+		flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY;
+	else
+		flags = TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		flags |= TEGRA_MMC_TRNMOD_CMD_CRC_CHECK;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		flags |= TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK;
+	if (data)
+		flags |= TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER;
+
+	debug("cmd: %d\n", cmd->cmdidx);
+
+	writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg);
+
+	for (i = 0; i < retry; i++) {
+		mask = readl(&host->reg->norintsts);
+		/* Command Complete */
+		if (mask & TEGRA_MMC_NORINTSTS_CMD_COMPLETE) {
+			if (!data)
+				writel(mask, &host->reg->norintsts);
+			break;
+		}
+	}
+
+	if (i == retry) {
+		printf("%s: waiting for status update\n", __func__);
+		writel(mask, &host->reg->norintsts);
+		return TIMEOUT;
+	}
+
+	if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) {
+		/* Timeout Error */
+		debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx);
+		writel(mask, &host->reg->norintsts);
+		return TIMEOUT;
+	} else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) {
+		/* Error Interrupt */
+		debug("error: %08x cmd %d\n", mask, cmd->cmdidx);
+		writel(mask, &host->reg->norintsts);
+		return -1;
+	}
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		if (cmd->resp_type & MMC_RSP_136) {
+			/* CRC is stripped so we need to do some shifting. */
+			for (i = 0; i < 4; i++) {
+				unsigned int offset =
+					(unsigned int)(&host->reg->rspreg3 - i);
+				cmd->response[i] = readl(offset) << 8;
+
+				if (i != 3) {
+					cmd->response[i] |=
+						readb(offset - 1);
+				}
+				debug("cmd->resp[%d]: %08x\n",
+						i, cmd->response[i]);
+			}
+		} else if (cmd->resp_type & MMC_RSP_BUSY) {
+			for (i = 0; i < retry; i++) {
+				/* PRNTDATA[23:20] : DAT[3:0] Line Signal */
+				if (readl(&host->reg->prnsts)
+					& (1 << 20))	/* DAT[0] */
+					break;
+			}
+
+			if (i == retry) {
+				printf("%s: card is still busy\n", __func__);
+				writel(mask, &host->reg->norintsts);
+				return TIMEOUT;
+			}
+
+			cmd->response[0] = readl(&host->reg->rspreg0);
+			debug("cmd->resp[0]: %08x\n", cmd->response[0]);
+		} else {
+			cmd->response[0] = readl(&host->reg->rspreg0);
+			debug("cmd->resp[0]: %08x\n", cmd->response[0]);
+		}
+	}
+
+	if (data) {
+		unsigned long	start = get_timer(0);
+
+		while (1) {
+			mask = readl(&host->reg->norintsts);
+
+			if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) {
+				/* Error Interrupt */
+				writel(mask, &host->reg->norintsts);
+				printf("%s: error during transfer: 0x%08x\n",
+						__func__, mask);
+				return -1;
+			} else if (mask & TEGRA_MMC_NORINTSTS_DMA_INTERRUPT) {
+				/*
+				 * DMA Interrupt, restart the transfer where
+				 * it was interrupted.
+				 */
+				unsigned int address = readl(&host->reg->sysad);
+
+				debug("DMA end\n");
+				writel(TEGRA_MMC_NORINTSTS_DMA_INTERRUPT,
+				       &host->reg->norintsts);
+				writel(address, &host->reg->sysad);
+			} else if (mask & TEGRA_MMC_NORINTSTS_XFER_COMPLETE) {
+				/* Transfer Complete */
+				debug("r/w is done\n");
+				break;
+			} else if (get_timer(start) > 2000UL) {
+				writel(mask, &host->reg->norintsts);
+				printf("%s: MMC Timeout\n"
+				       "    Interrupt status        0x%08x\n"
+				       "    Interrupt status enable 0x%08x\n"
+				       "    Interrupt signal enable 0x%08x\n"
+				       "    Present status          0x%08x\n",
+				       __func__, mask,
+				       readl(&host->reg->norintstsen),
+				       readl(&host->reg->norintsigen),
+				       readl(&host->reg->prnsts));
+				return -1;
+			}
+		}
+		writel(mask, &host->reg->norintsts);
+	}
+
+	udelay(1000);
+	return 0;
+}
+
+static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+			struct mmc_data *data)
+{
+	void *buf;
+	unsigned int bbflags;
+	size_t len;
+	struct bounce_buffer bbstate;
+	int ret;
+
+	if (data) {
+		if (data->flags & MMC_DATA_READ) {
+			buf = data->dest;
+			bbflags = GEN_BB_WRITE;
+		} else {
+			buf = (void *)data->src;
+			bbflags = GEN_BB_READ;
+		}
+		len = data->blocks * data->blocksize;
+
+		bounce_buffer_start(&bbstate, buf, len, bbflags);
+	}
+
+	ret = mmc_send_cmd_bounced(mmc, cmd, data, &bbstate);
+
+	if (data)
+		bounce_buffer_stop(&bbstate);
+
+	return ret;
+}
+
+static void mmc_change_clock(struct mmc_host *host, uint clock)
+{
+	int div;
+	unsigned short clk;
+	unsigned long timeout;
+
+	debug(" mmc_change_clock called\n");
+
+	/*
+	 * Change Tegra SDMMCx clock divisor here. Source is PLLP_OUT0
+	 */
+	if (clock == 0)
+		goto out;
+	clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock,
+				    &div);
+	debug("div = %d\n", div);
+
+	writew(0, &host->reg->clkcon);
+
+	/*
+	 * CLKCON
+	 * SELFREQ[15:8]	: base clock divided by value
+	 * ENSDCLK[2]		: SD Clock Enable
+	 * STBLINTCLK[1]	: Internal Clock Stable
+	 * ENINTCLK[0]		: Internal Clock Enable
+	 */
+	div >>= 1;
+	clk = ((div << TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT) |
+	       TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE);
+	writew(clk, &host->reg->clkcon);
+
+	/* Wait max 10 ms */
+	timeout = 10;
+	while (!(readw(&host->reg->clkcon) &
+		 TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE)) {
+		if (timeout == 0) {
+			printf("%s: timeout error\n", __func__);
+			return;
+		}
+		timeout--;
+		udelay(1000);
+	}
+
+	clk |= TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE;
+	writew(clk, &host->reg->clkcon);
+
+	debug("mmc_change_clock: clkcon = %08X\n", clk);
+
+out:
+	host->clock = clock;
+}
+
+static void mmc_set_ios(struct mmc *mmc)
+{
+	struct mmc_host *host = mmc->priv;
+	unsigned char ctrl;
+	debug(" mmc_set_ios called\n");
+
+	debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
+
+	/* Change clock first */
+	mmc_change_clock(host, mmc->clock);
+
+	ctrl = readb(&host->reg->hostctl);
+
+	/*
+	 * WIDE8[5]
+	 * 0 = Depend on WIDE4
+	 * 1 = 8-bit mode
+	 * WIDE4[1]
+	 * 1 = 4-bit mode
+	 * 0 = 1-bit mode
+	 */
+	if (mmc->bus_width == 8)
+		ctrl |= (1 << 5);
+	else if (mmc->bus_width == 4)
+		ctrl |= (1 << 1);
+	else
+		ctrl &= ~(1 << 1);
+
+	writeb(ctrl, &host->reg->hostctl);
+	debug("mmc_set_ios: hostctl = %08X\n", ctrl);
+}
+
+static void mmc_reset(struct mmc_host *host, struct mmc *mmc)
+{
+	unsigned int timeout;
+	debug(" mmc_reset called\n");
+
+	/*
+	 * RSTALL[0] : Software reset for all
+	 * 1 = reset
+	 * 0 = work
+	 */
+	writeb(TEGRA_MMC_SWRST_SW_RESET_FOR_ALL, &host->reg->swrst);
+
+	host->clock = 0;
+
+	/* Wait max 100 ms */
+	timeout = 100;
+
+	/* hw clears the bit when it's done */
+	while (readb(&host->reg->swrst) & TEGRA_MMC_SWRST_SW_RESET_FOR_ALL) {
+		if (timeout == 0) {
+			printf("%s: timeout error\n", __func__);
+			return;
+		}
+		timeout--;
+		udelay(1000);
+	}
+
+	/* Set SD bus voltage & enable bus power */
+	mmc_set_power(host, fls(mmc->voltages) - 1);
+	debug("%s: power control = %02X, host control = %02X\n", __func__,
+		readb(&host->reg->pwrcon), readb(&host->reg->hostctl));
+
+	/* Make sure SDIO pads are set up */
+	pad_init_mmc(host);
+}
+
+static int mmc_core_init(struct mmc *mmc)
+{
+	struct mmc_host *host = (struct mmc_host *)mmc->priv;
+	unsigned int mask;
+	debug(" mmc_core_init called\n");
+
+	mmc_reset(host, mmc);
+
+	host->version = readw(&host->reg->hcver);
+	debug("host version = %x\n", host->version);
+
+	/* mask all */
+	writel(0xffffffff, &host->reg->norintstsen);
+	writel(0xffffffff, &host->reg->norintsigen);
+
+	writeb(0xe, &host->reg->timeoutcon);	/* TMCLK * 2^27 */
+	/*
+	 * NORMAL Interrupt Status Enable Register init
+	 * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable
+	 * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable
+	 * [3] ENSTADMAINT   : DMA boundary interrupt
+	 * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable
+	 * [0] ENSTACMDCMPLT : Command Complete Status Enable
+	*/
+	mask = readl(&host->reg->norintstsen);
+	mask &= ~(0xffff);
+	mask |= (TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE |
+		 TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE |
+		 TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT |
+		 TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY |
+		 TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY);
+	writel(mask, &host->reg->norintstsen);
+
+	/*
+	 * NORMAL Interrupt Signal Enable Register init
+	 * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable
+	 */
+	mask = readl(&host->reg->norintsigen);
+	mask &= ~(0xffff);
+	mask |= TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE;
+	writel(mask, &host->reg->norintsigen);
+
+	return 0;
+}
+
+int tegra_mmc_getcd(struct mmc *mmc)
+{
+	struct mmc_host *host = (struct mmc_host *)mmc->priv;
+
+	debug("tegra_mmc_getcd called\n");
+
+	if (fdt_gpio_isvalid(&host->cd_gpio))
+		return fdtdec_get_gpio(&host->cd_gpio);
+
+	return 1;
+}
+
+static int do_mmc_init(int dev_index)
+{
+	struct mmc_host *host;
+	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
+	struct mmc *mmc;
+
+	/* DT should have been read & host config filled in */
+	host = &mmc_host[dev_index];
+	if (!host->enabled)
+		return -1;
+
+	debug(" do_mmc_init: index %d, bus width %d "
+		"pwr_gpio %d cd_gpio %d\n",
+		dev_index, host->width,
+		host->pwr_gpio.gpio, host->cd_gpio.gpio);
+
+	host->clock = 0;
+	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
+
+	if (fdt_gpio_isvalid(&host->pwr_gpio)) {
+		sprintf(gpusage, "SD/MMC%d PWR", dev_index);
+		gpio_request(host->pwr_gpio.gpio, gpusage);
+		gpio_direction_output(host->pwr_gpio.gpio, 1);
+		debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
+	}
+
+	if (fdt_gpio_isvalid(&host->cd_gpio)) {
+		sprintf(gpusage, "SD/MMC%d CD", dev_index);
+		gpio_request(host->cd_gpio.gpio, gpusage);
+		gpio_direction_input(host->cd_gpio.gpio);
+		debug(" CD GPIO name = %s\n", host->cd_gpio.name);
+	}
+
+	mmc = &mmc_dev[dev_index];
+
+	sprintf(mmc->name, "Tegra SD/MMC");
+	mmc->priv = host;
+	mmc->send_cmd = mmc_send_cmd;
+	mmc->set_ios = mmc_set_ios;
+	mmc->init = mmc_core_init;
+	mmc->getcd = tegra_mmc_getcd;
+	mmc->getwp = NULL;
+
+	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+	mmc->host_caps = 0;
+	if (host->width == 8)
+		mmc->host_caps |= MMC_MODE_8BIT;
+	if (host->width >= 4)
+		mmc->host_caps |= MMC_MODE_4BIT;
+	mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;
+
+	/*
+	 * min freq is for card identification, and is the highest
+	 *  low-speed SDIO card frequency (actually 400KHz)
+	 * max freq is highest HS eMMC clock as per the SD/MMC spec
+	 *  (actually 52MHz)
+	 */
+	mmc->f_min = 375000;
+	mmc->f_max = 48000000;
+
+	mmc_register(mmc);
+
+	return 0;
+}
+
+/**
+ * Get the host address and peripheral ID for a node.
+ *
+ * @param blob		fdt blob
+ * @param node		Device index (0-3)
+ * @param host		Structure to fill in (reg, width, mmc_id)
+ */
+static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
+{
+	debug("%s: node = %d\n", __func__, node);
+
+	host->enabled = fdtdec_get_is_enabled(blob, node);
+
+	host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg");
+	if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) {
+		debug("%s: no sdmmc base reg info found\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	host->mmc_id = clock_decode_periph_id(blob, node);
+	if (host->mmc_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/*
+	 * NOTE: mmc->bus_width is determined by mmc.c dynamically.
+	 * TBD: Override it with this value?
+	 */
+	host->width = fdtdec_get_int(blob, node, "bus-width", 0);
+	if (!host->width)
+		debug("%s: no sdmmc width found\n", __func__);
+
+	/* These GPIOs are optional */
+	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+	fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
+	fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
+
+	debug("%s: found controller at %p, width = %d, periph_id = %d\n",
+		__func__, host->reg, host->width, host->mmc_id);
+	return 0;
+}
+
+/*
+ * Process a list of nodes, adding them to our list of SDMMC ports.
+ *
+ * @param blob          fdt blob
+ * @param node_list     list of nodes to process (any <=0 are ignored)
+ * @param count         number of nodes to process
+ * @return 0 if ok, -1 on error
+ */
+static int process_nodes(const void *blob, int node_list[], int count)
+{
+	struct mmc_host *host;
+	int i, node;
+
+	debug("%s: count = %d\n", __func__, count);
+
+	/* build mmc_host[] for each controller */
+	for (i = 0; i < count; i++) {
+		node = node_list[i];
+		if (node <= 0)
+			continue;
+
+		host = &mmc_host[i];
+		host->id = i;
+
+		if (mmc_get_config(blob, node, host)) {
+			printf("%s: failed to decode dev %d\n",	__func__, i);
+			return -1;
+		}
+		do_mmc_init(i);
+	}
+	return 0;
+}
+
+void tegra_mmc_init(void)
+{
+	int node_list[MAX_HOSTS], count;
+	const void *blob = gd->fdt_blob;
+	debug("%s entry\n", __func__);
+
+	/* See if any Tegra30 MMC controllers are present */
+	count = fdtdec_find_aliases_for_id(blob, "sdhci",
+		COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS);
+	debug("%s: count of T30 sdhci nodes is %d\n", __func__, count);
+	if (process_nodes(blob, node_list, count)) {
+		printf("%s: Error processing T30 mmc node(s)!\n", __func__);
+		return;
+	}
+
+	/* Now look for any Tegra20 MMC controllers */
+	count = fdtdec_find_aliases_for_id(blob, "sdhci",
+		COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS);
+	debug("%s: count of T20 sdhci nodes is %d\n", __func__, count);
+	if (process_nodes(blob, node_list, count)) {
+		printf("%s: Error processing T20 mmc node(s)!\n", __func__);
+		return;
+	}
+}
diff --git a/marvell/uboot/drivers/mmc/zynq_sdhci.c b/marvell/uboot/drivers/mmc/zynq_sdhci.c
new file mode 100644
index 0000000..610bef5
--- /dev/null
+++ b/marvell/uboot/drivers/mmc/zynq_sdhci.c
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2013 Inc.
+ *
+ * Xilinx Zynq SD Host Controller Interface
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/arch/sys_proto.h>
+
+int zynq_sdhci_init(u32 regbase)
+{
+	struct sdhci_host *host = NULL;
+
+	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+	if (!host) {
+		printf("zynq_sdhci_init: sdhci_host malloc fail\n");
+		return 1;
+	}
+
+	host->name = "zynq_sdhci";
+	host->ioaddr = (void *)regbase;
+	host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD;
+	host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+	host->host_caps = MMC_MODE_HC;
+
+	add_sdhci(host, 52000000, 52000000 >> 9);
+	return 0;
+}