summaryrefslogtreecommitdiffstats
path: root/u-boot/drivers/mmc
diff options
context:
space:
mode:
authorH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
committerH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
commit92988a21ad4c4c9504295ccb580c9f806134471b (patch)
tree5effc9f14170112450de05c67dafbe8d5034d595 /u-boot/drivers/mmc
parentca2b506783b676c95762c54ea24dcfdaae1947c9 (diff)
downloadbootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.zip
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.gz
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.bz2
added boot script files to repository
Diffstat (limited to 'u-boot/drivers/mmc')
-rw-r--r--u-boot/drivers/mmc/Makefile56
-rw-r--r--u-boot/drivers/mmc/atmel_mci.c533
-rw-r--r--u-boot/drivers/mmc/atmel_mci.h245
-rw-r--r--u-boot/drivers/mmc/bfin_sdh.c262
-rw-r--r--u-boot/drivers/mmc/davinci_mmc.c403
-rw-r--r--u-boot/drivers/mmc/fsl_esdhc.c544
-rw-r--r--u-boot/drivers/mmc/gen_atmel_mci.c354
-rw-r--r--u-boot/drivers/mmc/mmc.c948
-rw-r--r--u-boot/drivers/mmc/mxcmmc.c522
-rw-r--r--u-boot/drivers/mmc/omap3_mmc.c570
-rw-r--r--u-boot/drivers/mmc/omap3_mmc.h233
-rw-r--r--u-boot/drivers/mmc/omap_hsmmc.c471
-rw-r--r--u-boot/drivers/mmc/pxa_mmc.c647
-rw-r--r--u-boot/drivers/mmc/pxa_mmc.h138
-rw-r--r--u-boot/drivers/mmc/s5p_mmc.c477
15 files changed, 6403 insertions, 0 deletions
diff --git a/u-boot/drivers/mmc/Makefile b/u-boot/drivers/mmc/Makefile
new file mode 100644
index 0000000..3496f0a
--- /dev/null
+++ b/u-boot/drivers/mmc/Makefile
@@ -0,0 +1,56 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libmmc.o
+
+COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
+COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
+COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
+COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
+COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
+COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
+COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
+COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
+COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
+COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/u-boot/drivers/mmc/atmel_mci.c b/u-boot/drivers/mmc/atmel_mci.c
new file mode 100644
index 0000000..3946ffe
--- /dev/null
+++ b/u-boot/drivers/mmc/atmel_mci.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/memory-map.h>
+
+#include "atmel_mci.h"
+
+#ifdef DEBUG
+#define pr_debug(fmt, args...) printf(fmt, ##args)
+#else
+#define pr_debug(...) do { } while(0)
+#endif
+
+#ifndef CONFIG_SYS_MMC_CLK_OD
+#define CONFIG_SYS_MMC_CLK_OD 150000
+#endif
+
+#ifndef CONFIG_SYS_MMC_CLK_PP
+#define CONFIG_SYS_MMC_CLK_PP 5000000
+#endif
+
+#ifndef CONFIG_SYS_MMC_OP_COND
+#define CONFIG_SYS_MMC_OP_COND 0x00100000
+#endif
+
+#define MMC_DEFAULT_BLKLEN 512
+#define MMC_DEFAULT_RCA 1
+
+static unsigned int mmc_rca;
+static int mmc_card_is_sd;
+static block_dev_desc_t mmc_blkdev;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+ return &mmc_blkdev;
+}
+
+static void mci_set_mode(unsigned long hz, unsigned long blklen)
+{
+ unsigned long bus_hz;
+ unsigned long clkdiv;
+
+ bus_hz = get_mci_clk_rate();
+ clkdiv = (bus_hz / hz) / 2 - 1;
+
+ pr_debug("mmc: setting clock %lu Hz, block size %lu\n",
+ hz, blklen);
+
+ if (clkdiv & ~255UL) {
+ clkdiv = 255;
+ printf("mmc: clock %lu too low; setting CLKDIV to 255\n",
+ hz);
+ }
+
+ blklen &= 0xfffc;
+ mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv)
+ | MMCI_BF(BLKLEN, blklen)
+ | MMCI_BIT(RDPROOF)
+ | MMCI_BIT(WRPROOF)));
+}
+
+#define RESP_NO_CRC 1
+#define R1 MMCI_BF(RSPTYP, 1)
+#define R2 MMCI_BF(RSPTYP, 2)
+#define R3 (R1 | RESP_NO_CRC)
+#define R6 R1
+#define NID MMCI_BF(MAXLAT, 0)
+#define NCR MMCI_BF(MAXLAT, 1)
+#define TRCMD_START MMCI_BF(TRCMD, 1)
+#define TRDIR_READ MMCI_BF(TRDIR, 1)
+#define TRTYP_BLOCK MMCI_BF(TRTYP, 0)
+#define INIT_CMD MMCI_BF(SPCMD, 1)
+#define OPEN_DRAIN MMCI_BF(OPDCMD, 1)
+
+#define ERROR_FLAGS (MMCI_BIT(DTOE) \
+ | MMCI_BIT(RDIRE) \
+ | MMCI_BIT(RENDE) \
+ | MMCI_BIT(RINDE) \
+ | MMCI_BIT(RTOE))
+
+static int
+mmc_cmd(unsigned long cmd, unsigned long arg,
+ void *resp, unsigned long flags)
+{
+ unsigned long *response = resp;
+ int i, response_words = 0;
+ unsigned long error_flags;
+ u32 status;
+
+ pr_debug("mmc: CMD%lu 0x%lx (flags 0x%lx)\n",
+ cmd, arg, flags);
+
+ error_flags = ERROR_FLAGS;
+ if (!(flags & RESP_NO_CRC))
+ error_flags |= MMCI_BIT(RCRCE);
+
+ flags &= ~MMCI_BF(CMDNB, ~0UL);
+
+ if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_48_BIT_RESP)
+ response_words = 1;
+ else if (MMCI_BFEXT(RSPTYP, flags) == MMCI_RSPTYP_136_BIT_RESP)
+ response_words = 4;
+
+ mmci_writel(ARGR, arg);
+ mmci_writel(CMDR, cmd | flags);
+ do {
+ udelay(40);
+ status = mmci_readl(SR);
+ } while (!(status & MMCI_BIT(CMDRDY)));
+
+ pr_debug("mmc: status 0x%08x\n", status);
+
+ if (status & error_flags) {
+ printf("mmc: command %lu failed (status: 0x%08x)\n",
+ cmd, status);
+ return -EIO;
+ }
+
+ if (response_words)
+ pr_debug("mmc: response:");
+
+ for (i = 0; i < response_words; i++) {
+ response[i] = mmci_readl(RSPR);
+ pr_debug(" %08lx", response[i]);
+ }
+ pr_debug("\n");
+
+ return 0;
+}
+
+static int mmc_acmd(unsigned long cmd, unsigned long arg,
+ void *resp, unsigned long flags)
+{
+ unsigned long aresp[4];
+ int ret;
+
+ /*
+ * Seems like the APP_CMD part of an ACMD has 64 cycles max
+ * latency even though the ACMD part doesn't. This isn't
+ * entirely clear in the SD Card spec, but some cards refuse
+ * to work if we attempt to use 5 cycles max latency here...
+ */
+ ret = mmc_cmd(MMC_CMD_APP_CMD, 0, aresp,
+ R1 | NCR | (flags & OPEN_DRAIN));
+ if (ret)
+ return ret;
+ if ((aresp[0] & (R1_ILLEGAL_COMMAND | R1_APP_CMD)) != R1_APP_CMD)
+ return -ENODEV;
+
+ ret = mmc_cmd(cmd, arg, resp, flags);
+ return ret;
+}
+
+static unsigned long
+mmc_bread(int dev, unsigned long start, lbaint_t blkcnt,
+ void *buffer)
+{
+ int ret, i = 0;
+ unsigned long resp[4];
+ unsigned long card_status, data;
+ unsigned long wordcount;
+ u32 *p = buffer;
+ u32 status;
+
+ if (blkcnt == 0)
+ return 0;
+
+ pr_debug("mmc_bread: dev %d, start %lx, blkcnt %lx\n",
+ dev, start, blkcnt);
+
+ /* Put the device into Transfer state */
+ ret = mmc_cmd(MMC_CMD_SELECT_CARD, mmc_rca << 16, resp, R1 | NCR);
+ if (ret) goto out;
+
+ /* Set block length */
+ ret = mmc_cmd(MMC_CMD_SET_BLOCKLEN, mmc_blkdev.blksz, resp, R1 | NCR);
+ if (ret) goto out;
+
+ pr_debug("MCI_DTOR = %08lx\n", mmci_readl(DTOR));
+
+ for (i = 0; i < blkcnt; i++, start++) {
+ ret = mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK,
+ start * mmc_blkdev.blksz, resp,
+ (R1 | NCR | TRCMD_START | TRDIR_READ
+ | TRTYP_BLOCK));
+ if (ret) goto out;
+
+ ret = -EIO;
+ wordcount = 0;
+ do {
+ do {
+ status = mmci_readl(SR);
+ if (status & (ERROR_FLAGS | MMCI_BIT(OVRE)))
+ goto read_error;
+ } while (!(status & MMCI_BIT(RXRDY)));
+
+ if (status & MMCI_BIT(RXRDY)) {
+ data = mmci_readl(RDR);
+ /* pr_debug("%x\n", data); */
+ *p++ = data;
+ wordcount++;
+ }
+ } while(wordcount < (mmc_blkdev.blksz / 4));
+
+ pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount);
+
+ do {
+ status = mmci_readl(SR);
+ } while (!(status & MMCI_BIT(BLKE)));
+
+ putc('.');
+ }
+
+out:
+ /* Put the device back into Standby state */
+ mmc_cmd(MMC_CMD_SELECT_CARD, 0, resp, NCR);
+ return i;
+
+read_error:
+ mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR);
+ printf("mmc: bread failed, status = %08x, card status = %08lx\n",
+ status, card_status);
+ goto out;
+}
+
+static void mmc_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+ cid->mid = resp[0] >> 24;
+ cid->oid = (resp[0] >> 8) & 0xffff;
+ cid->pnm[0] = resp[0];
+ cid->pnm[1] = resp[1] >> 24;
+ cid->pnm[2] = resp[1] >> 16;
+ cid->pnm[3] = resp[1] >> 8;
+ cid->pnm[4] = resp[1];
+ cid->pnm[5] = resp[2] >> 24;
+ cid->pnm[6] = 0;
+ cid->prv = resp[2] >> 16;
+ cid->psn = (resp[2] << 16) | (resp[3] >> 16);
+ cid->mdt = resp[3] >> 8;
+}
+
+static void sd_parse_cid(struct mmc_cid *cid, unsigned long *resp)
+{
+ cid->mid = resp[0] >> 24;
+ cid->oid = (resp[0] >> 8) & 0xffff;
+ cid->pnm[0] = resp[0];
+ cid->pnm[1] = resp[1] >> 24;
+ cid->pnm[2] = resp[1] >> 16;
+ cid->pnm[3] = resp[1] >> 8;
+ cid->pnm[4] = resp[1];
+ cid->pnm[5] = 0;
+ cid->pnm[6] = 0;
+ cid->prv = resp[2] >> 24;
+ cid->psn = (resp[2] << 8) | (resp[3] >> 24);
+ cid->mdt = (resp[3] >> 8) & 0x0fff;
+}
+
+static void mmc_dump_cid(const struct mmc_cid *cid)
+{
+ printf("Manufacturer ID: %02X\n", cid->mid);
+ printf("OEM/Application ID: %04X\n", cid->oid);
+ printf("Product name: %s\n", cid->pnm);
+ printf("Product Revision: %u.%u\n",
+ cid->prv >> 4, cid->prv & 0x0f);
+ printf("Product Serial Number: %lu\n", cid->psn);
+ printf("Manufacturing Date: %02u/%02u\n",
+ cid->mdt >> 4, cid->mdt & 0x0f);
+}
+
+static void mmc_dump_csd(const struct mmc_csd *csd)
+{
+ unsigned long *csd_raw = (unsigned long *)csd;
+ printf("CSD data: %08lx %08lx %08lx %08lx\n",
+ csd_raw[0], csd_raw[1], csd_raw[2], csd_raw[3]);
+ printf("CSD structure version: 1.%u\n", csd->csd_structure);
+ printf("MMC System Spec version: %u\n", csd->spec_vers);
+ printf("Card command classes: %03x\n", csd->ccc);
+ printf("Read block length: %u\n", 1 << csd->read_bl_len);
+ if (csd->read_bl_partial)
+ puts("Supports partial reads\n");
+ else
+ puts("Does not support partial reads\n");
+ printf("Write block length: %u\n", 1 << csd->write_bl_len);
+ if (csd->write_bl_partial)
+ puts("Supports partial writes\n");
+ else
+ puts("Does not support partial writes\n");
+ if (csd->wp_grp_enable)
+ printf("Supports group WP: %u\n", csd->wp_grp_size + 1);
+ else
+ puts("Does not support group WP\n");
+ printf("Card capacity: %u bytes\n",
+ (csd->c_size + 1) * (1 << (csd->c_size_mult + 2)) *
+ (1 << csd->read_bl_len));
+ printf("File format: %u/%u\n",
+ csd->file_format_grp, csd->file_format);
+ puts("Write protection: ");
+ if (csd->perm_write_protect)
+ puts(" permanent");
+ if (csd->tmp_write_protect)
+ puts(" temporary");
+ putc('\n');
+}
+
+static int mmc_idle_cards(void)
+{
+ int ret;
+
+ /* Reset and initialize all cards */
+ ret = mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, NULL, 0);
+ if (ret)
+ return ret;
+
+ /* Keep the bus idle for 74 clock cycles */
+ return mmc_cmd(0, 0, NULL, INIT_CMD);
+}
+
+static int sd_init_card(struct mmc_cid *cid, int verbose)
+{
+ unsigned long resp[4];
+ int i, ret = 0;
+
+ mmc_idle_cards();
+ for (i = 0; i < 1000; i++) {
+ ret = mmc_acmd(SD_CMD_APP_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND,
+ resp, R3 | NID);
+ if (ret || (resp[0] & 0x80000000))
+ break;
+ ret = -ETIMEDOUT;
+ }
+
+ if (ret)
+ return ret;
+
+ ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID);
+ if (ret)
+ return ret;
+ sd_parse_cid(cid, resp);
+ if (verbose)
+ mmc_dump_cid(cid);
+
+ /* Get RCA of the card that responded */
+ ret = mmc_cmd(SD_CMD_SEND_RELATIVE_ADDR, 0, resp, R6 | NCR);
+ if (ret)
+ return ret;
+
+ mmc_rca = resp[0] >> 16;
+ if (verbose)
+ printf("SD Card detected (RCA %u)\n", mmc_rca);
+ mmc_card_is_sd = 1;
+ return 0;
+}
+
+static int mmc_init_card(struct mmc_cid *cid, int verbose)
+{
+ unsigned long resp[4];
+ int i, ret = 0;
+
+ mmc_idle_cards();
+ for (i = 0; i < 1000; i++) {
+ ret = mmc_cmd(MMC_CMD_SEND_OP_COND, CONFIG_SYS_MMC_OP_COND, resp,
+ R3 | NID | OPEN_DRAIN);
+ if (ret || (resp[0] & 0x80000000))
+ break;
+ ret = -ETIMEDOUT;
+ }
+
+ if (ret)
+ return ret;
+
+ /* Get CID of all cards. FIXME: Support more than one card */
+ ret = mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, resp, R2 | NID | OPEN_DRAIN);
+ if (ret)
+ return ret;
+ mmc_parse_cid(cid, resp);
+ if (verbose)
+ mmc_dump_cid(cid);
+
+ /* Set Relative Address of the card that responded */
+ ret = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, mmc_rca << 16, resp,
+ R1 | NCR | OPEN_DRAIN);
+ return ret;
+}
+
+static void mci_set_data_timeout(struct mmc_csd *csd)
+{
+ static const unsigned int dtomul_to_shift[] = {
+ 0, 4, 7, 8, 10, 12, 16, 20,
+ };
+ static const unsigned int taac_exp[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+ };
+ static const unsigned int taac_mant[] = {
+ 0, 10, 12, 13, 15, 60, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+ };
+ unsigned int timeout_ns, timeout_clks;
+ unsigned int e, m;
+ unsigned int dtocyc, dtomul;
+ unsigned int shift;
+ u32 dtor;
+
+ e = csd->taac & 0x07;
+ m = (csd->taac >> 3) & 0x0f;
+
+ timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
+ timeout_clks = csd->nsac * 100;
+
+ timeout_clks += (((timeout_ns + 9) / 10)
+ * ((CONFIG_SYS_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000;
+ if (!mmc_card_is_sd)
+ timeout_clks *= 10;
+ else
+ timeout_clks *= 100;
+
+ dtocyc = timeout_clks;
+ dtomul = 0;
+ shift = 0;
+ while (dtocyc > 15 && dtomul < 8) {
+ dtomul++;
+ shift = dtomul_to_shift[dtomul];
+ dtocyc = (timeout_clks + (1 << shift) - 1) >> shift;
+ }
+
+ if (dtomul >= 8) {
+ dtomul = 7;
+ dtocyc = 15;
+ puts("Warning: Using maximum data timeout\n");
+ }
+
+ dtor = (MMCI_BF(DTOMUL, dtomul)
+ | MMCI_BF(DTOCYC, dtocyc));
+ mmci_writel(DTOR, dtor);
+
+ printf("mmc: Using %u cycles data timeout (DTOR=0x%x)\n",
+ dtocyc << shift, dtor);
+}
+
+int mmc_legacy_init(int verbose)
+{
+ struct mmc_cid cid;
+ struct mmc_csd csd;
+ unsigned int max_blksz;
+ int ret;
+
+ /* Initialize controller */
+ mmci_writel(CR, MMCI_BIT(SWRST));
+ mmci_writel(CR, MMCI_BIT(MCIEN));
+ mmci_writel(DTOR, 0x5f);
+ mmci_writel(IDR, ~0UL);
+ mci_set_mode(CONFIG_SYS_MMC_CLK_OD, MMC_DEFAULT_BLKLEN);
+
+ mmc_card_is_sd = 0;
+
+ ret = sd_init_card(&cid, verbose);
+ if (ret) {
+ mmc_rca = MMC_DEFAULT_RCA;
+ ret = mmc_init_card(&cid, verbose);
+ }
+ if (ret)
+ return ret;
+
+ /* Get CSD from the card */
+ ret = mmc_cmd(MMC_CMD_SEND_CSD, mmc_rca << 16, &csd, R2 | NCR);
+ if (ret)
+ return ret;
+ if (verbose)
+ mmc_dump_csd(&csd);
+
+ mci_set_data_timeout(&csd);
+
+ /* Initialize the blockdev structure */
+ mmc_blkdev.if_type = IF_TYPE_MMC;
+ mmc_blkdev.part_type = PART_TYPE_DOS;
+ mmc_blkdev.block_read = mmc_bread;
+ sprintf((char *)mmc_blkdev.vendor,
+ "Man %02x%04x Snr %08lx",
+ cid.mid, cid.oid, cid.psn);
+ strncpy((char *)mmc_blkdev.product, cid.pnm,
+ sizeof(mmc_blkdev.product));
+ sprintf((char *)mmc_blkdev.revision, "%x %x",
+ cid.prv >> 4, cid.prv & 0x0f);
+
+ /*
+ * If we can't use 512 byte blocks, refuse to deal with the
+ * card. Tons of code elsewhere seems to depend on this.
+ */
+ max_blksz = 1 << csd.read_bl_len;
+ if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) {
+ printf("Card does not support 512 byte reads, aborting.\n");
+ return -ENODEV;
+ }
+ mmc_blkdev.blksz = 512;
+ mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2));
+
+ mci_set_mode(CONFIG_SYS_MMC_CLK_PP, mmc_blkdev.blksz);
+
+#if 0
+ if (fat_register_device(&mmc_blkdev, 1))
+ printf("Could not register MMC fat device\n");
+#else
+ init_part(&mmc_blkdev);
+#endif
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/atmel_mci.h b/u-boot/drivers/mmc/atmel_mci.h
new file mode 100644
index 0000000..823a77d
--- /dev/null
+++ b/u-boot/drivers/mmc/atmel_mci.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef __CPU_AT32AP_ATMEL_MCI_H__
+#define __CPU_AT32AP_ATMEL_MCI_H__
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Structure for struct SoC access.
+ * Names starting with '_' are fillers.
+ */
+typedef struct atmel_mci {
+ /* reg Offset */
+ u32 cr; /* 0x00 */
+ u32 mr; /* 0x04 */
+ u32 dtor; /* 0x08 */
+ u32 sdcr; /* 0x0c */
+ u32 argr; /* 0x10 */
+ u32 cmdr; /* 0x14 */
+ u32 _18; /* 0x18 */
+ u32 _1c; /* 0x1c */
+ u32 rspr; /* 0x20 */
+ u32 rspr1; /* 0x24 */
+ u32 rspr2; /* 0x28 */
+ u32 rspr3; /* 0x2c */
+ u32 rdr; /* 0x30 */
+ u32 tdr; /* 0x34 */
+ u32 _38; /* 0x38 */
+ u32 _3c; /* 0x3c */
+ u32 sr; /* 0x40 */
+ u32 ier; /* 0x44 */
+ u32 idr; /* 0x48 */
+ u32 imr; /* 0x4c */
+} atmel_mci_t;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * NOTICE: Use of registers offsets is depreciated.
+ * These defines will be removed once the old driver
+ * is taken out of commision.
+ *
+ * Atmel MultiMedia Card Interface (MCI) registers
+ */
+#define MMCI_CR 0x0000
+#define MMCI_MR 0x0004
+#define MMCI_DTOR 0x0008
+#define MMCI_SDCR 0x000c
+#define MMCI_ARGR 0x0010
+#define MMCI_CMDR 0x0014
+#define MMCI_RSPR 0x0020
+#define MMCI_RSPR1 0x0024
+#define MMCI_RSPR2 0x0028
+#define MMCI_RSPR3 0x002c
+#define MMCI_RDR 0x0030
+#define MMCI_TDR 0x0034
+#define MMCI_SR 0x0040
+#define MMCI_IER 0x0044
+#define MMCI_IDR 0x0048
+#define MMCI_IMR 0x004c
+
+/* Bitfields in CR */
+#define MMCI_MCIEN_OFFSET 0
+#define MMCI_MCIEN_SIZE 1
+#define MMCI_MCIDIS_OFFSET 1
+#define MMCI_MCIDIS_SIZE 1
+#define MMCI_PWSEN_OFFSET 2
+#define MMCI_PWSEN_SIZE 1
+#define MMCI_PWSDIS_OFFSET 3
+#define MMCI_PWSDIS_SIZE 1
+#define MMCI_SWRST_OFFSET 7
+#define MMCI_SWRST_SIZE 1
+
+/* Bitfields in MR */
+#define MMCI_CLKDIV_OFFSET 0
+#define MMCI_CLKDIV_SIZE 8
+#define MMCI_PWSDIV_OFFSET 8
+#define MMCI_PWSDIV_SIZE 3
+#define MMCI_RDPROOF_OFFSET 11
+#define MMCI_RDPROOF_SIZE 1
+#define MMCI_WRPROOF_OFFSET 12
+#define MMCI_WRPROOF_SIZE 1
+#define MMCI_PDCPADV_OFFSET 14
+#define MMCI_PDCPADV_SIZE 1
+#define MMCI_PDCMODE_OFFSET 15
+#define MMCI_PDCMODE_SIZE 1
+#define MMCI_BLKLEN_OFFSET 16
+#define MMCI_BLKLEN_SIZE 16
+
+/* Bitfields in DTOR */
+#define MMCI_DTOCYC_OFFSET 0
+#define MMCI_DTOCYC_SIZE 4
+#define MMCI_DTOMUL_OFFSET 4
+#define MMCI_DTOMUL_SIZE 3
+
+/* Bitfields in SDCR */
+#define MMCI_SCDSEL_OFFSET 0
+#define MMCI_SCDSEL_SIZE 4
+#define MMCI_SCDBUS_OFFSET 7
+#define MMCI_SCDBUS_SIZE 1
+
+/* Bitfields in ARGR */
+#define MMCI_ARG_OFFSET 0
+#define MMCI_ARG_SIZE 32
+
+/* Bitfields in CMDR */
+#define MMCI_CMDNB_OFFSET 0
+#define MMCI_CMDNB_SIZE 6
+#define MMCI_RSPTYP_OFFSET 6
+#define MMCI_RSPTYP_SIZE 2
+#define MMCI_SPCMD_OFFSET 8
+#define MMCI_SPCMD_SIZE 3
+#define MMCI_OPDCMD_OFFSET 11
+#define MMCI_OPDCMD_SIZE 1
+#define MMCI_MAXLAT_OFFSET 12
+#define MMCI_MAXLAT_SIZE 1
+#define MMCI_TRCMD_OFFSET 16
+#define MMCI_TRCMD_SIZE 2
+#define MMCI_TRDIR_OFFSET 18
+#define MMCI_TRDIR_SIZE 1
+#define MMCI_TRTYP_OFFSET 19
+#define MMCI_TRTYP_SIZE 2
+
+/* Bitfields in RSPRx */
+#define MMCI_RSP_OFFSET 0
+#define MMCI_RSP_SIZE 32
+
+/* Bitfields in SR/IER/IDR/IMR */
+#define MMCI_CMDRDY_OFFSET 0
+#define MMCI_CMDRDY_SIZE 1
+#define MMCI_RXRDY_OFFSET 1
+#define MMCI_RXRDY_SIZE 1
+#define MMCI_TXRDY_OFFSET 2
+#define MMCI_TXRDY_SIZE 1
+#define MMCI_BLKE_OFFSET 3
+#define MMCI_BLKE_SIZE 1
+#define MMCI_DTIP_OFFSET 4
+#define MMCI_DTIP_SIZE 1
+#define MMCI_NOTBUSY_OFFSET 5
+#define MMCI_NOTBUSY_SIZE 1
+#define MMCI_ENDRX_OFFSET 6
+#define MMCI_ENDRX_SIZE 1
+#define MMCI_ENDTX_OFFSET 7
+#define MMCI_ENDTX_SIZE 1
+#define MMCI_RXBUFF_OFFSET 14
+#define MMCI_RXBUFF_SIZE 1
+#define MMCI_TXBUFE_OFFSET 15
+#define MMCI_TXBUFE_SIZE 1
+#define MMCI_RINDE_OFFSET 16
+#define MMCI_RINDE_SIZE 1
+#define MMCI_RDIRE_OFFSET 17
+#define MMCI_RDIRE_SIZE 1
+#define MMCI_RCRCE_OFFSET 18
+#define MMCI_RCRCE_SIZE 1
+#define MMCI_RENDE_OFFSET 19
+#define MMCI_RENDE_SIZE 1
+#define MMCI_RTOE_OFFSET 20
+#define MMCI_RTOE_SIZE 1
+#define MMCI_DCRCE_OFFSET 21
+#define MMCI_DCRCE_SIZE 1
+#define MMCI_DTOE_OFFSET 22
+#define MMCI_DTOE_SIZE 1
+#define MMCI_OVRE_OFFSET 30
+#define MMCI_OVRE_SIZE 1
+#define MMCI_UNRE_OFFSET 31
+#define MMCI_UNRE_SIZE 1
+
+/* Constants for DTOMUL */
+#define MMCI_DTOMUL_1_CYCLE 0
+#define MMCI_DTOMUL_16_CYCLES 1
+#define MMCI_DTOMUL_128_CYCLES 2
+#define MMCI_DTOMUL_256_CYCLES 3
+#define MMCI_DTOMUL_1024_CYCLES 4
+#define MMCI_DTOMUL_4096_CYCLES 5
+#define MMCI_DTOMUL_65536_CYCLES 6
+#define MMCI_DTOMUL_1048576_CYCLES 7
+
+/* Constants for RSPTYP */
+#define MMCI_RSPTYP_NO_RESP 0
+#define MMCI_RSPTYP_48_BIT_RESP 1
+#define MMCI_RSPTYP_136_BIT_RESP 2
+
+/* Constants for SPCMD */
+#define MMCI_SPCMD_NO_SPEC_CMD 0
+#define MMCI_SPCMD_INIT_CMD 1
+#define MMCI_SPCMD_SYNC_CMD 2
+#define MMCI_SPCMD_INT_CMD 4
+#define MMCI_SPCMD_INT_RESP 5
+
+/* Constants for TRCMD */
+#define MMCI_TRCMD_NO_TRANS 0
+#define MMCI_TRCMD_START_TRANS 1
+#define MMCI_TRCMD_STOP_TRANS 2
+
+/* Constants for TRTYP */
+#define MMCI_TRTYP_BLOCK 0
+#define MMCI_TRTYP_MULTI_BLOCK 1
+#define MMCI_TRTYP_STREAM 2
+
+/* Bit manipulation macros */
+#define MMCI_BIT(name) \
+ (1 << MMCI_##name##_OFFSET)
+#define MMCI_BF(name,value) \
+ (((value) & ((1 << MMCI_##name##_SIZE) - 1)) \
+ << MMCI_##name##_OFFSET)
+#define MMCI_BFEXT(name,value) \
+ (((value) >> MMCI_##name##_OFFSET)\
+ & ((1 << MMCI_##name##_SIZE) - 1))
+#define MMCI_BFINS(name,value,old) \
+ (((old) & ~(((1 << MMCI_##name##_SIZE) - 1) \
+ << MMCI_##name##_OFFSET)) \
+ | MMCI_BF(name,value))
+
+/*
+ * NOTICE: Use of registers offsets is depreciated.
+ * These defines will be removed once the old driver
+ * is taken out of commision.
+ *
+ * Register access macros
+ */
+#define mmci_readl(reg) \
+ readl((void *)MMCI_BASE + MMCI_##reg)
+#define mmci_writel(reg,value) \
+ writel((value), (void *)MMCI_BASE + MMCI_##reg)
+
+#endif /* __CPU_AT32AP_ATMEL_MCI_H__ */
diff --git a/u-boot/drivers/mmc/bfin_sdh.c b/u-boot/drivers/mmc/bfin_sdh.c
new file mode 100644
index 0000000..27d9bf6
--- /dev/null
+++ b/u-boot/drivers/mmc/bfin_sdh.c
@@ -0,0 +1,262 @@
+/*
+ * 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(__ADSPBF51x__)
+# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CONTROL
+# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CONTROL
+# 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
+# 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
+# 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;
+
+ 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);
+
+ 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;
+ int ret = 0;
+
+ /* Don't support write yet. */
+ if (data->flags & MMC_DATA_WRITE)
+ return UNUSABLE_ERR;
+ data_ctl |= ((ffs(data->blocksize) - 1) << 4);
+ data_ctl |= DTX_DIR;
+ bfin_write_SDH_DATA_CTL(data_ctl);
+ dma_cfg = WDSIZE_32 | RESTART | WNR | DMAEN;
+
+ bfin_write_SDH_DATA_TIMER(0xFFFF);
+
+ blackfin_dcache_flush_invalidate_range(data->dest,
+ data->dest + data->blocksize);
+ /* configure DMA */
+ bfin_write_DMA_START_ADDR(data->dest);
+ bfin_write_DMA_X_COUNT(data->blocksize / 4);
+ bfin_write_DMA_X_MODIFY(4);
+ bfin_write_DMA_CONFIG(dma_cfg);
+ bfin_write_SDH_DATA_LGTH(data->blocksize);
+ /* kick off transfer */
+ bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
+
+ return ret;
+}
+
+
+static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ u32 status;
+ int ret = 0;
+
+ ret = sdh_send_cmd(mmc, cmd);
+ if (ret) {
+ printf("sending CMD%d failed\n", cmd->cmdidx);
+ return ret;
+ }
+ if (data) {
+ ret = sdh_setup_data(mmc, 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();
+ cfg &= ~0x80;
+ cfg |= 0x40;
+ bfin_write_SDH_CFG(cfg);
+ clk_ctl |= WIDE_BUS;
+ }
+ 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;
+ u16 pwr_ctl = 0;
+
+ /* Initialize sdh controller */
+ peripheral_request_list(pins, "bfin_sdh");
+#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);
+
+ pwr_ctl |= ROD_CTL;
+ pwr_ctl |= PWR_ON;
+ bfin_write_SDH_PWR_CTL(pwr_ctl);
+ 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->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->block_dev.part_type = PART_TYPE_DOS;
+
+ mmc_register(mmc);
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/davinci_mmc.c b/u-boot/drivers/mmc/davinci_mmc.c
new file mode 100644
index 0000000..d5d19eb
--- /dev/null
+++ b/u-boot/drivers/mmc/davinci_mmc.c
@@ -0,0 +1,403 @@
+/*
+ * Davinci MMC Controller Driver
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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 mmcstatus1, wdog = WATCHDOG_COUNT;
+ mmcstatus1 = get_val(&regs->mmcst1);
+ 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 mmcstatus1, wdog = WATCHDOG_COUNT;
+
+ mmcstatus1 = get_val(&regs->mmcst1);
+ 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);
+
+ 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->f_min = 200000;
+ mmc->f_max = 25000000;
+ mmc->voltages = host->voltages;
+ mmc->host_caps = host->host_caps;
+
+#ifdef CONFIG_MMC_MBLOCK
+ mmc->b_max = DAVINCI_MAX_BLOCKS;
+#endif
+ mmc_register(mmc);
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/fsl_esdhc.c b/u-boot/drivers/mmc/fsl_esdhc.c
new file mode 100644
index 0000000..f3cccbe
--- /dev/null
+++ b/u-boot/drivers/mmc/fsl_esdhc.c
@@ -0,0 +1,544 @@
+/*
+ * 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
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <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;
+ uint blkattr;
+ uint cmdarg;
+ uint xfertyp;
+ uint cmdrsp0;
+ uint cmdrsp1;
+ uint cmdrsp2;
+ uint cmdrsp3;
+ uint datport;
+ uint prsstat;
+ uint proctl;
+ uint sysctl;
+ uint irqstat;
+ uint irqstaten;
+ uint irqsigen;
+ uint autoc12err;
+ uint hostcapblt;
+ uint wml;
+ char reserved1[8];
+ uint fevt;
+ char reserved2[168];
+ uint hostver;
+ char reserved3[780];
+ uint scr;
+};
+
+/* Return the XFERTYP flags for a given command and data packet */
+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;
+
+ 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 *regs = mmc->priv;
+ 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 > 0x10)
+ wml_value = 0x10;
+
+ esdhc_clrsetbits32(&regs->wml, WML_RD_WML_MASK, wml_value);
+ esdhc_write32(&regs->dsaddr, (u32)data->dest);
+ } else {
+ if (wml_value > 0x80)
+ wml_value = 0x80;
+ 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 */
+ timeout = fls(mmc->tran_speed/10) - 1;
+ 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;
+}
+
+
+/*
+ * 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);
+
+ /* Send the command */
+ esdhc_write32(&regs->cmdarg, cmd->cmdarg);
+ esdhc_write32(&regs->xfertyp, xfertyp);
+
+ /* Wait for the command to complete */
+ while (!(esdhc_read32(&regs->irqstat) & IRQSTAT_CC))
+ ;
+
+ irqstat = esdhc_read32(&regs->irqstat);
+ esdhc_write32(&regs->irqstat, irqstat);
+
+ if (irqstat & CMD_ERR)
+ return COMM_ERR;
+
+ if (irqstat & IRQSTAT_CTOE)
+ 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 & DATA_ERR)
+ return COMM_ERR;
+
+ if (irqstat & IRQSTAT_DTOE)
+ return TIMEOUT;
+ } while (!(irqstat & IRQSTAT_TC) &&
+ (esdhc_read32(&regs->prsstat) & PRSSTAT_DLA));
+#endif
+ }
+
+ esdhc_write32(&regs->irqstat, -1);
+
+ return 0;
+}
+
+void set_sysctl(struct mmc *mmc, uint clock)
+{
+ int sdhc_clk = gd->sdhc_clk;
+ 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;
+ 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;
+ int ret = 0;
+ u8 card_absent;
+
+ /* Reset the entire host controller */
+ esdhc_write32(&regs->sysctl, SYSCTL_RSTA);
+
+ /* Wait until the controller is available */
+ while ((esdhc_read32(&regs->sysctl) & SYSCTL_RSTA) && --timeout)
+ udelay(1000);
+
+ /* Enable cache snooping */
+ if (cfg && !cfg->no_snoop)
+ esdhc_write32(&regs->scr, 0x00000040);
+
+ esdhc_write32(&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);
+
+ /* Check if there is a callback for detecting the card */
+ if (board_mmc_getcd(&card_absent, mmc)) {
+ timeout = 1000;
+ while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) &&
+ --timeout)
+ udelay(1000);
+
+ if (timeout <= 0)
+ ret = NO_CARD_ERR;
+ } else {
+ if (card_absent)
+ ret = NO_CARD_ERR;
+ }
+
+ return ret;
+}
+
+static void esdhc_reset(struct fsl_esdhc *regs)
+{
+ unsigned long timeout = 100; /* wait max 100 ms */
+
+ /* reset the controller */
+ esdhc_write32(&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));
+
+ sprintf(mmc->name, "FSL_ESDHC");
+ regs = (struct fsl_esdhc *)cfg->esdhc_base;
+
+ /* First reset the eSDHC controller */
+ esdhc_reset(regs);
+
+ mmc->priv = cfg;
+ mmc->send_cmd = esdhc_send_cmd;
+ mmc->set_ios = esdhc_set_ios;
+ mmc->init = esdhc_init;
+
+ voltage_caps = 0;
+ caps = regs->hostcapblt;
+
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC135
+ caps = caps & ~(ESDHC_HOSTCAPBLT_SRS |
+ ESDHC_HOSTCAPBLT_VS18 | ESDHC_HOSTCAPBLT_VS30);
+#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;
+
+ if (caps & ESDHC_HOSTCAPBLT_HSS)
+ mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ mmc->f_min = 400000;
+ mmc->f_max = MIN(gd->sdhc_clk, 52000000);
+
+ mmc_register(mmc);
+
+ return 0;
+}
+
+int fsl_esdhc_mmc_init(bd_t *bis)
+{
+ struct fsl_esdhc_cfg *cfg;
+
+ cfg = malloc(sizeof(struct fsl_esdhc_cfg));
+ memset(cfg, 0, sizeof(struct fsl_esdhc_cfg));
+ cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR;
+ 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->sdhc_clk, 1);
+
+ do_fixup_by_compat(blob, compat, "status", "okay",
+ 4 + 1, 1);
+}
+#endif
diff --git a/u-boot/drivers/mmc/gen_atmel_mci.c b/u-boot/drivers/mmc/gen_atmel_mci.c
new file mode 100644
index 0000000..2984d64
--- /dev/null
+++ b/u-boot/drivers/mmc/gen_atmel_mci.c
@@ -0,0 +1,354 @@
+/*
+ * 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
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <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/memory-map.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;
+
+/*
+ * 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);
+ 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);
+
+ /* 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) {
+ 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 busw = (mmc->bus_width == 4) ? 1 : 0;
+
+ /* 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
+ * Bitfield SCDBUS needs to be expanded to 2 bits for 8-bit buses
+ */
+ writel(MMCI_BF(SCDBUS, busw) | 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 */
+
+ /* Initial Time-outs */
+ writel(0x5f, &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));
+
+ 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;
+
+ /* need to be able to pass these in on a board by board basis */
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ 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_register(mmc);
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/mmc.c b/u-boot/drivers/mmc/mmc.c
new file mode 100644
index 0000000..6805b33
--- /dev/null
+++ b/u-boot/drivers/mmc/mmc.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright 2008, Freescale Semiconductor, Inc
+ * Andy Fleming
+ *
+ * Based vaguely on the Linux code
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <mmc.h>
+#include <part.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <mmc.h>
+#include <div64.h>
+
+static struct list_head mmc_devices;
+static int cur_dev_num = -1;
+
+int __board_mmc_getcd(u8 *cd, struct mmc *mmc) {
+ return -1;
+}
+
+int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak,
+ alias("__board_mmc_getcd")));
+
+int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+ return mmc->send_cmd(mmc, cmd, data);
+}
+
+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;
+ cmd.flags = 0;
+
+ 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;
+ }
+
+ printf("MMC Device %d not found\n", dev_num);
+
+ return NULL;
+}
+
+static ulong
+mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+
+ if ((start + blkcnt) > mmc->block_dev.lba) {
+ printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
+ start + blkcnt, mmc->block_dev.lba);
+ return 0;
+ }
+
+ if (blkcnt > 1)
+ cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+ else
+ cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
+
+ if (mmc->high_capacity)
+ cmd.cmdarg = start;
+ else
+ cmd.cmdarg = start * mmc->write_bl_len;
+
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.flags = 0;
+
+ 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;
+ }
+
+ if (blkcnt > 1) {
+ cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.flags = 0;
+ if (mmc_send_cmd(mmc, &cmd, NULL)) {
+ printf("mmc fail to send stop cmd\n");
+ return 0;
+ }
+ }
+
+ return blkcnt;
+}
+
+static ulong
+mmc_bwrite(int dev_num, ulong 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 {
+ /*
+ * The 65535 constraint comes from some hardware has
+ * only 16 bit width block number counter
+ */
+ cur = (blocks_todo > 65535) ? 65535 : 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;
+}
+
+int mmc_read_blocks(struct mmc *mmc, void *dst, ulong 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;
+ cmd.flags = 0;
+
+ 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;
+ cmd.flags = 0;
+ if (mmc_send_cmd(mmc, &cmd, NULL)) {
+ printf("mmc fail to send stop cmd\n");
+ return 0;
+ }
+ }
+
+ return blkcnt;
+}
+
+static ulong mmc_bread(int dev_num, ulong 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) {
+ printf("MMC: block number 0x%lx exceeds max(0x%lx)\n",
+ start + blkcnt, mmc->block_dev.lba);
+ return 0;
+ }
+
+ if (mmc_set_blocklen(mmc, mmc->read_bl_len))
+ return 0;
+
+ do {
+ /*
+ * The 65535 constraint comes from some hardware has
+ * only 16 bit width block number counter
+ */
+ cur = (blocks_todo > 65535) ? 65535 : blocks_todo;
+ if(mmc_read_blocks(mmc, dst, start, cur) != cur)
+ return 0;
+ blocks_todo -= cur;
+ start += cur;
+ dst += cur * mmc->read_bl_len;
+ } while (blocks_todo > 0);
+
+ return blkcnt;
+}
+
+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;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+
+ udelay(2000);
+
+ return 0;
+}
+
+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;
+ cmd.flags = 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->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;
+
+ mmc->ocr = cmd.response[0];
+
+ mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+ mmc->rca = 0;
+
+ return 0;
+}
+
+int mmc_send_op_cond(struct mmc *mmc)
+{
+ int timeout = 1000;
+ struct mmc_cmd cmd;
+ int err;
+
+ /* Some cards seem to need this */
+ mmc_go_idle(mmc);
+
+ do {
+ cmd.cmdidx = MMC_CMD_SEND_OP_COND;
+ cmd.resp_type = MMC_RSP_R3;
+ cmd.cmdarg = OCR_HCS | mmc->voltages;
+ cmd.flags = 0;
+
+ 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;
+
+ mmc->version = MMC_VERSION_UNKNOWN;
+ mmc->ocr = cmd.response[0];
+
+ mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
+ mmc->rca = 0;
+
+ return 0;
+}
+
+
+int mmc_send_ext_csd(struct mmc *mmc, char *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;
+ cmd.flags = 0;
+
+ data.dest = ext_csd;
+ data.blocks = 1;
+ data.blocksize = 512;
+ data.flags = MMC_DATA_READ;
+
+ err = mmc_send_cmd(mmc, &cmd, &data);
+
+ return err;
+}
+
+
+int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+{
+ struct mmc_cmd cmd;
+
+ cmd.cmdidx = MMC_CMD_SWITCH;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (index << 16) |
+ (value << 8);
+ cmd.flags = 0;
+
+ return mmc_send_cmd(mmc, &cmd, NULL);
+}
+
+int mmc_change_freq(struct mmc *mmc)
+{
+ char ext_csd[512];
+ char cardtype;
+ int err;
+
+ mmc->card_caps = 0;
+
+ /* Only version 4 supports high-speed */
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
+
+ mmc->card_caps |= MMC_MODE_4BIT;
+
+ err = mmc_send_ext_csd(mmc, ext_csd);
+
+ if (err)
+ return err;
+
+ if (ext_csd[212] || ext_csd[213] || ext_csd[214] || ext_csd[215])
+ mmc->high_capacity = 1;
+
+ cardtype = ext_csd[196] & 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[185])
+ 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;
+}
+
+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);
+ cmd.flags = 0;
+
+ data.dest = (char *)resp;
+ data.blocksize = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+
+ return mmc_send_cmd(mmc, &cmd, &data);
+}
+
+
+int sd_change_freq(struct mmc *mmc)
+{
+ int err;
+ struct mmc_cmd cmd;
+ uint scr[2];
+ uint switch_status[16];
+ struct mmc_data data;
+ int timeout;
+
+ mmc->card_caps = 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;
+ cmd.flags = 0;
+
+ 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;
+ cmd.flags = 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;
+ break;
+ default:
+ mmc->version = SD_VERSION_1_0;
+ break;
+ }
+
+ /* 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 (mmc->scr[0] & SD_DATA_4BIT)
+ mmc->card_caps |= MMC_MODE_4BIT;
+
+ /* If high-speed isn't supported, we return */
+ if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
+ 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 */
+int fbase[] = {
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+};
+
+/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
+ * to platforms without floating point.
+ */
+int multipliers[] = {
+ 0, /* reserved */
+ 10,
+ 12,
+ 13,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 45,
+ 50,
+ 55,
+ 60,
+ 70,
+ 80,
+};
+
+void mmc_set_ios(struct mmc *mmc)
+{
+ mmc->set_ios(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);
+}
+
+void mmc_set_bus_width(struct mmc *mmc, uint width)
+{
+ mmc->bus_width = width;
+
+ mmc_set_ios(mmc);
+}
+
+int mmc_startup(struct mmc *mmc)
+{
+ int err;
+ uint mult, freq;
+ u64 cmult, csize;
+ struct mmc_cmd cmd;
+ char ext_csd[512];
+
+ /* Put the Card in Identify Mode */
+ cmd.cmdidx = MMC_CMD_ALL_SEND_CID;
+ cmd.resp_type = MMC_RSP_R2;
+ cmd.cmdarg = 0;
+ cmd.flags = 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
+ */
+ cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.resp_type = MMC_RSP_R6;
+ cmd.flags = 0;
+
+ 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;
+ cmd.flags = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ 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->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 = (csize + 1) << (cmult + 2);
+ mmc->capacity *= mmc->read_bl_len;
+
+ if (mmc->read_bl_len > 512)
+ mmc->read_bl_len = 512;
+
+ if (mmc->write_bl_len > 512)
+ mmc->write_bl_len = 512;
+
+ /* Select the card, and put it into Transfer Mode */
+ cmd.cmdidx = MMC_CMD_SELECT_CARD;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.flags = 0;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+
+ 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[192] >= 2)) {
+ mmc->capacity = ext_csd[212] << 0 | ext_csd[213] << 8 |
+ ext_csd[214] << 16 | ext_csd[215] << 24;
+ mmc->capacity *= 512;
+ }
+ }
+
+ 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;
+ cmd.flags = 0;
+
+ 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;
+ cmd.flags = 0;
+ 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_set_clock(mmc, 50000000);
+ else
+ mmc_set_clock(mmc, 25000000);
+ } else {
+ if (mmc->card_caps & MMC_MODE_4BIT) {
+ /* Set the card to use 4 bit*/
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ EXT_CSD_BUS_WIDTH_4);
+
+ if (err)
+ return err;
+
+ mmc_set_bus_width(mmc, 4);
+ } else if (mmc->card_caps & MMC_MODE_8BIT) {
+ /* Set the card to use 8 bit*/
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ EXT_CSD_BUS_WIDTH_8);
+
+ if (err)
+ return err;
+
+ mmc_set_bus_width(mmc, 8);
+ }
+
+ if (mmc->card_caps & MMC_MODE_HS) {
+ if (mmc->card_caps & MMC_MODE_HS_52MHz)
+ mmc_set_clock(mmc, 52000000);
+ else
+ mmc_set_clock(mmc, 26000000);
+ } else
+ mmc_set_clock(mmc, 20000000);
+ }
+
+ /* 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.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+ sprintf(mmc->block_dev.vendor, "Man %06x Snr %08x", mmc->cid[0] >> 8,
+ (mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
+ sprintf(mmc->block_dev.product, "%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);
+ sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
+ (mmc->cid[2] >> 24) & 0xf);
+ init_part(&mmc->block_dev);
+
+ return 0;
+}
+
+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;
+ cmd.flags = 0;
+
+ 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;
+}
+
+int mmc_register(struct mmc *mmc)
+{
+ /* 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;
+
+ INIT_LIST_HEAD (&mmc->link);
+
+ list_add_tail (&mmc->link, &mmc_devices);
+
+ return 0;
+}
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+ struct mmc *mmc = find_mmc_device(dev);
+
+ return mmc ? &mmc->block_dev : NULL;
+}
+
+int mmc_init(struct mmc *mmc)
+{
+ int err;
+
+ err = mmc->init(mmc);
+
+ if (err)
+ return err;
+
+ mmc_set_bus_width(mmc, 1);
+ mmc_set_clock(mmc, 1);
+
+ /* Reset the Card */
+ err = mmc_go_idle(mmc);
+
+ if (err)
+ return err;
+
+ /* 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) {
+ printf("Card did not respond to voltage select!\n");
+ return UNUSABLE_ERR;
+ }
+ }
+
+ return mmc_startup(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")));
+
+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");
+}
+
+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);
+
+ print_mmc_devices(',');
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/mxcmmc.c b/u-boot/drivers/mmc/mxcmmc.c
new file mode 100644
index 0000000..5963953
--- /dev/null
+++ b/u-boot/drivers/mmc/mxcmmc.c
@@ -0,0 +1,522 @@
+/*
+ * 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>
+#ifdef CONFIG_MX27
+#include <asm/arch/clock.h>
+#endif
+
+#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 = imx_get_perclk2();
+
+ 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->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 = imx_get_perclk2() >> 7;
+ mmc->f_max = imx_get_perclk2() >> 1;
+
+ mmc_register(mmc);
+
+ return 0;
+}
+
+int mxc_mmc_init(bd_t *bis)
+{
+ return mxcmci_initialize(bis);
+}
diff --git a/u-boot/drivers/mmc/omap3_mmc.c b/u-boot/drivers/mmc/omap3_mmc.c
new file mode 100644
index 0000000..15d41e5
--- /dev/null
+++ b/u-boot/drivers/mmc/omap3_mmc.c
@@ -0,0 +1,570 @@
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Syed Mohammed Khasim <khasim@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 <fat.h>
+#include <mmc.h>
+#include <part.h>
+#include <i2c.h>
+#include <twl4030.h>
+#include <asm/io.h>
+
+#include "omap3_mmc.h"
+
+static const unsigned short mmc_transspeed_val[15][4] = {
+ {CLKD(10, 1), CLKD(10, 10), CLKD(10, 100), CLKD(10, 1000)},
+ {CLKD(12, 1), CLKD(12, 10), CLKD(12, 100), CLKD(12, 1000)},
+ {CLKD(13, 1), CLKD(13, 10), CLKD(13, 100), CLKD(13, 1000)},
+ {CLKD(15, 1), CLKD(15, 10), CLKD(15, 100), CLKD(15, 1000)},
+ {CLKD(20, 1), CLKD(20, 10), CLKD(20, 100), CLKD(20, 1000)},
+ {CLKD(26, 1), CLKD(26, 10), CLKD(26, 100), CLKD(26, 1000)},
+ {CLKD(30, 1), CLKD(30, 10), CLKD(30, 100), CLKD(30, 1000)},
+ {CLKD(35, 1), CLKD(35, 10), CLKD(35, 100), CLKD(35, 1000)},
+ {CLKD(40, 1), CLKD(40, 10), CLKD(40, 100), CLKD(40, 1000)},
+ {CLKD(45, 1), CLKD(45, 10), CLKD(45, 100), CLKD(45, 1000)},
+ {CLKD(52, 1), CLKD(52, 10), CLKD(52, 100), CLKD(52, 1000)},
+ {CLKD(55, 1), CLKD(55, 10), CLKD(55, 100), CLKD(55, 1000)},
+ {CLKD(60, 1), CLKD(60, 10), CLKD(60, 100), CLKD(60, 1000)},
+ {CLKD(70, 1), CLKD(70, 10), CLKD(70, 100), CLKD(70, 1000)},
+ {CLKD(80, 1), CLKD(80, 10), CLKD(80, 100), CLKD(80, 1000)}
+};
+
+static mmc_card_data cur_card_data;
+static block_dev_desc_t mmc_blk_dev;
+static hsmmc_t *mmc_base = (hsmmc_t *)OMAP_HSMMC1_BASE;
+
+int mmc_set_dev(int dev_num)
+{
+ switch (dev_num) {
+ case 1:
+ mmc_base = (hsmmc_t *)OMAP_HSMMC1_BASE;
+ break;
+ case 2:
+ mmc_base = (hsmmc_t *)OMAP_HSMMC2_BASE;
+ break;
+ case 3:
+ mmc_base = (hsmmc_t *)OMAP_HSMMC3_BASE;
+ break;
+ default:
+ mmc_base = (hsmmc_t *)OMAP_HSMMC1_BASE;
+ return 1;
+ }
+
+ return 0;
+}
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+ return (block_dev_desc_t *) &mmc_blk_dev;
+}
+
+static unsigned char mmc_board_init(void)
+{
+#if defined(CONFIG_TWL4030_POWER)
+ twl4030_power_mmc_init();
+#endif
+
+#if defined(CONFIG_OMAP34XX)
+ t2_t *t2_base = (t2_t *)T2_BASE;
+ struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+
+ writel(readl(&t2_base->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);
+
+ 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
+
+/* TODO add appropriate OMAP4 init */
+
+ return 1;
+}
+
+static void mmc_init_stream(void)
+{
+ writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
+
+ writel(MMC_CMD0, &mmc_base->cmd);
+ while (!(readl(&mmc_base->stat) & CC_MASK));
+
+ writel(CC_MASK, &mmc_base->stat);
+
+ writel(MMC_CMD0, &mmc_base->cmd);
+ while (!(readl(&mmc_base->stat) & CC_MASK));
+
+ writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
+}
+
+static unsigned char mmc_clock_config(unsigned int iclk, unsigned short clk_div)
+{
+ unsigned int val;
+
+ mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+ (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+
+ switch (iclk) {
+ case CLK_INITSEQ:
+ val = MMC_INIT_SEQ_CLK / 2;
+ break;
+ case CLK_400KHZ:
+ val = MMC_400kHz_CLK;
+ break;
+ case CLK_MISC:
+ val = clk_div;
+ break;
+ default:
+ return 0;
+ }
+ mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+ (val << CLKD_OFFSET) | ICE_OSCILLATE);
+
+ while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY);
+
+ writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+ return 1;
+}
+
+static unsigned char mmc_init_setup(void)
+{
+ unsigned int reg_val;
+
+ mmc_board_init();
+
+ writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
+ &mmc_base->sysconfig);
+ while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0);
+
+ writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
+ while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0);
+
+ 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);
+
+ mmc_clock_config(CLK_INITSEQ, 0);
+ 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();
+ return 1;
+}
+
+static unsigned char mmc_send_cmd(unsigned int cmd, unsigned int arg,
+ unsigned int *response)
+{
+ unsigned int mmc_stat;
+
+ while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS);
+
+ writel(BLEN_512BYTESLEN | NBLK_STPCNT, &mmc_base->blk);
+ writel(0xFFFFFFFF, &mmc_base->stat);
+ writel(arg, &mmc_base->arg);
+ writel(cmd | CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
+ MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE,
+ &mmc_base->cmd);
+
+ while (1) {
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0)
+ return (unsigned char) mmc_stat;
+
+ if (mmc_stat & CC_MASK) {
+ writel(CC_MASK, &mmc_base->stat);
+ response[0] = readl(&mmc_base->rsp10);
+ if ((cmd & RSP_TYPE_MASK) == RSP_TYPE_LGHT136) {
+ response[1] = readl(&mmc_base->rsp32);
+ response[2] = readl(&mmc_base->rsp54);
+ response[3] = readl(&mmc_base->rsp76);
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+static unsigned char mmc_read_data(unsigned int *output_buf)
+{
+ unsigned int mmc_stat;
+ unsigned int read_count = 0;
+
+ /*
+ * Start Polled Read
+ */
+ while (1) {
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0)
+ return (unsigned char) mmc_stat;
+
+ if (mmc_stat & BRR_MASK) {
+ unsigned int k;
+
+ writel(readl(&mmc_base->stat) | BRR_MASK,
+ &mmc_base->stat);
+ for (k = 0; k < MMCSD_SECTOR_SIZE / 4; k++) {
+ *output_buf = readl(&mmc_base->data);
+ output_buf++;
+ read_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 1;
+}
+
+static unsigned char mmc_detect_card(mmc_card_data *mmc_card_cur)
+{
+ unsigned char err;
+ unsigned int argument = 0;
+ unsigned int ocr_value, ocr_recvd, ret_cmd41, hcs_val;
+ unsigned short retry_cnt = 2000;
+ mmc_resp_t mmc_resp;
+
+ /* Set to Initialization Clock */
+ err = mmc_clock_config(CLK_400KHZ, 0);
+ if (err != 1)
+ return err;
+
+ mmc_card_cur->RCA = MMC_RELATIVE_CARD_ADDRESS;
+ argument = 0x00000000;
+
+ ocr_value = (0x1FF << 15);
+ err = mmc_send_cmd(MMC_CMD0, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+
+ argument = SD_CMD8_CHECK_PATTERN | SD_CMD8_2_7_3_6_V_RANGE;
+ err = mmc_send_cmd(MMC_SDCMD8, argument, mmc_resp.resp);
+ hcs_val = (err == 1) ?
+ MMC_OCR_REG_HOST_CAPACITY_SUPPORT_SECTOR :
+ MMC_OCR_REG_HOST_CAPACITY_SUPPORT_BYTE;
+
+ argument = 0x0000 << 16;
+ err = mmc_send_cmd(MMC_CMD55, argument, mmc_resp.resp);
+ if (err == 1) {
+ mmc_card_cur->card_type = SD_CARD;
+ ocr_value |= hcs_val;
+ ret_cmd41 = MMC_ACMD41;
+ } else {
+ mmc_card_cur->card_type = MMC_CARD;
+ ocr_value |= MMC_OCR_REG_ACCESS_MODE_SECTOR;
+ ret_cmd41 = MMC_CMD1;
+ writel(readl(&mmc_base->con) & ~OD, &mmc_base->con);
+ writel(readl(&mmc_base->con) | OPENDRAIN, &mmc_base->con);
+ }
+
+ argument = ocr_value;
+ err = mmc_send_cmd(ret_cmd41, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+
+ ocr_recvd = mmc_resp.r3.ocr;
+
+ while (!(ocr_recvd & (0x1 << 31)) && (retry_cnt > 0)) {
+ retry_cnt--;
+ if (mmc_card_cur->card_type == SD_CARD) {
+ argument = 0x0000 << 16;
+ err = mmc_send_cmd(MMC_CMD55, argument, mmc_resp.resp);
+ }
+
+ argument = ocr_value;
+ err = mmc_send_cmd(ret_cmd41, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+ ocr_recvd = mmc_resp.r3.ocr;
+ }
+
+ if (!(ocr_recvd & (0x1 << 31)))
+ return 0;
+
+ if (mmc_card_cur->card_type == MMC_CARD) {
+ if ((ocr_recvd & MMC_OCR_REG_ACCESS_MODE_MASK) ==
+ MMC_OCR_REG_ACCESS_MODE_SECTOR) {
+ mmc_card_cur->mode = SECTOR_MODE;
+ } else {
+ mmc_card_cur->mode = BYTE_MODE;
+ }
+
+ ocr_recvd &= ~MMC_OCR_REG_ACCESS_MODE_MASK;
+ } else {
+ if ((ocr_recvd & MMC_OCR_REG_HOST_CAPACITY_SUPPORT_MASK)
+ == MMC_OCR_REG_HOST_CAPACITY_SUPPORT_SECTOR) {
+ mmc_card_cur->mode = SECTOR_MODE;
+ } else {
+ mmc_card_cur->mode = BYTE_MODE;
+ }
+ ocr_recvd &= ~MMC_OCR_REG_HOST_CAPACITY_SUPPORT_MASK;
+ }
+
+ ocr_recvd &= ~(0x1 << 31);
+ if (!(ocr_recvd & ocr_value))
+ return 0;
+
+ err = mmc_send_cmd(MMC_CMD2, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+
+ if (mmc_card_cur->card_type == MMC_CARD) {
+ argument = mmc_card_cur->RCA << 16;
+ err = mmc_send_cmd(MMC_CMD3, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+ } else {
+ argument = 0x00000000;
+ err = mmc_send_cmd(MMC_SDCMD3, argument, mmc_resp.resp);
+ if (err != 1)
+ return err;
+
+ mmc_card_cur->RCA = mmc_resp.r6.newpublishedrca;
+ }
+
+ writel(readl(&mmc_base->con) & ~OD, &mmc_base->con);
+ writel(readl(&mmc_base->con) | NOOPENDRAIN, &mmc_base->con);
+ return 1;
+}
+
+static unsigned char mmc_read_cardsize(mmc_card_data *mmc_dev_data,
+ mmc_csd_reg_t *cur_csd)
+{
+ mmc_extended_csd_reg_t ext_csd;
+ unsigned int size, count, blk_len, blk_no, card_size, argument;
+ unsigned char err;
+ unsigned int resp[4];
+
+ if (mmc_dev_data->mode == SECTOR_MODE) {
+ if (mmc_dev_data->card_type == SD_CARD) {
+ card_size =
+ (((mmc_sd2_csd_reg_t *) cur_csd)->
+ c_size_lsb & MMC_SD2_CSD_C_SIZE_LSB_MASK) |
+ ((((mmc_sd2_csd_reg_t *) cur_csd)->
+ c_size_msb & MMC_SD2_CSD_C_SIZE_MSB_MASK)
+ << MMC_SD2_CSD_C_SIZE_MSB_OFFSET);
+ mmc_dev_data->size = card_size * 1024;
+ if (mmc_dev_data->size == 0)
+ return 0;
+ } else {
+ argument = 0x00000000;
+ err = mmc_send_cmd(MMC_CMD8, argument, resp);
+ if (err != 1)
+ return err;
+ err = mmc_read_data((unsigned int *) &ext_csd);
+ if (err != 1)
+ return err;
+ mmc_dev_data->size = ext_csd.sectorcount;
+
+ if (mmc_dev_data->size == 0)
+ mmc_dev_data->size = 8388608;
+ }
+ } else {
+ if (cur_csd->c_size_mult >= 8)
+ return 0;
+
+ if (cur_csd->read_bl_len >= 12)
+ return 0;
+
+ /* Compute size */
+ count = 1 << (cur_csd->c_size_mult + 2);
+ card_size = (cur_csd->c_size_lsb & MMC_CSD_C_SIZE_LSB_MASK) |
+ ((cur_csd->c_size_msb & MMC_CSD_C_SIZE_MSB_MASK)
+ << MMC_CSD_C_SIZE_MSB_OFFSET);
+ blk_no = (card_size + 1) * count;
+ blk_len = 1 << cur_csd->read_bl_len;
+ size = blk_no * blk_len;
+ mmc_dev_data->size = size / MMCSD_SECTOR_SIZE;
+ if (mmc_dev_data->size == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static unsigned long mmc_bread(int dev_num, unsigned long blknr,
+ lbaint_t blkcnt, void *dst)
+{
+ unsigned char err;
+ unsigned int argument;
+ unsigned int resp[4];
+ unsigned int *output_buf = dst;
+ unsigned int sec_inc_val;
+ lbaint_t i;
+
+ if (blkcnt == 0)
+ return 0;
+
+ if (cur_card_data.mode == SECTOR_MODE) {
+ argument = blknr;
+ sec_inc_val = 1;
+ } else {
+ argument = blknr * MMCSD_SECTOR_SIZE;
+ sec_inc_val = MMCSD_SECTOR_SIZE;
+ }
+
+ for (i = 0; i < blkcnt; i++) {
+ err = mmc_send_cmd(MMC_CMD17, argument, resp);
+ if (err != 1) {
+ printf("mmc: CMD17 failed, status = %08x\n", err);
+ break;
+ }
+
+ err = mmc_read_data(output_buf);
+ if (err != 1) {
+ printf("mmc: read failed, status = %08x\n", err);
+ break;
+ }
+
+ output_buf += (MMCSD_SECTOR_SIZE / 4);
+ argument += sec_inc_val;
+ }
+
+ return i;
+}
+
+static unsigned char configure_mmc(mmc_card_data *mmc_card_cur)
+{
+ unsigned char ret_val;
+ unsigned int argument;
+ unsigned int trans_clk, trans_fact, trans_unit, retries = 2;
+ unsigned char trans_speed;
+ mmc_resp_t mmc_resp;
+
+ ret_val = mmc_init_setup();
+
+ if (ret_val != 1)
+ return ret_val;
+
+ do {
+ ret_val = mmc_detect_card(mmc_card_cur);
+ retries--;
+ } while ((retries > 0) && (ret_val != 1));
+
+ argument = mmc_card_cur->RCA << 16;
+ ret_val = mmc_send_cmd(MMC_CMD9, argument, mmc_resp.resp);
+ if (ret_val != 1)
+ return ret_val;
+
+ if (mmc_card_cur->card_type == MMC_CARD)
+ mmc_card_cur->version = mmc_resp.Card_CSD.spec_vers;
+
+ trans_speed = mmc_resp.Card_CSD.tran_speed;
+
+ ret_val = mmc_send_cmd(MMC_CMD4, MMC_DSR_DEFAULT << 16, mmc_resp.resp);
+ if (ret_val != 1)
+ return ret_val;
+
+ trans_unit = trans_speed & MMC_CSD_TRAN_SPEED_UNIT_MASK;
+ trans_fact = trans_speed & MMC_CSD_TRAN_SPEED_FACTOR_MASK;
+
+ if (trans_unit > MMC_CSD_TRAN_SPEED_UNIT_100MHZ)
+ return 0;
+
+ if ((trans_fact < MMC_CSD_TRAN_SPEED_FACTOR_1_0) ||
+ (trans_fact > MMC_CSD_TRAN_SPEED_FACTOR_8_0))
+ return 0;
+
+ trans_unit >>= 0;
+ trans_fact >>= 3;
+
+ trans_clk = mmc_transspeed_val[trans_fact - 1][trans_unit] * 2;
+ ret_val = mmc_clock_config(CLK_MISC, trans_clk);
+
+ if (ret_val != 1)
+ return ret_val;
+
+ argument = mmc_card_cur->RCA << 16;
+ ret_val = mmc_send_cmd(MMC_CMD7_SELECT, argument, mmc_resp.resp);
+ if (ret_val != 1)
+ return ret_val;
+
+ /* Configure the block length to 512 bytes */
+ argument = MMCSD_SECTOR_SIZE;
+ ret_val = mmc_send_cmd(MMC_CMD16, argument, mmc_resp.resp);
+ if (ret_val != 1)
+ return ret_val;
+
+ /* get the card size in sectors */
+ ret_val = mmc_read_cardsize(mmc_card_cur, &mmc_resp.Card_CSD);
+ if (ret_val != 1)
+ return ret_val;
+
+ return 1;
+}
+
+int mmc_legacy_init(int dev)
+{
+ if (mmc_set_dev(dev) != 0)
+ return 1;
+
+ if (configure_mmc(&cur_card_data) != 1)
+ return 1;
+
+ mmc_blk_dev.if_type = IF_TYPE_MMC;
+ mmc_blk_dev.part_type = PART_TYPE_DOS;
+ mmc_blk_dev.dev = 0;
+ mmc_blk_dev.lun = 0;
+ mmc_blk_dev.type = 0;
+
+ /* FIXME fill in the correct size (is set to 32MByte) */
+ mmc_blk_dev.blksz = MMCSD_SECTOR_SIZE;
+ mmc_blk_dev.lba = 0x10000;
+ mmc_blk_dev.removable = 0;
+ mmc_blk_dev.block_read = mmc_bread;
+
+ fat_register_device(&mmc_blk_dev, 1);
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/omap3_mmc.h b/u-boot/drivers/mmc/omap3_mmc.h
new file mode 100644
index 0000000..e4d263c
--- /dev/null
+++ b/u-boot/drivers/mmc/omap3_mmc.h
@@ -0,0 +1,233 @@
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Syed Mohammed Khasim <khasim@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
+ */
+
+#ifndef MMC_H
+#define MMC_H
+
+#include <asm/arch/mmc_host_def.h>
+
+/* Responses */
+#define RSP_TYPE_NONE (RSP_TYPE_NORSP | CCCE_NOCHECK | CICE_NOCHECK)
+#define RSP_TYPE_R1 (RSP_TYPE_LGHT48 | CCCE_CHECK | CICE_CHECK)
+#define RSP_TYPE_R1B (RSP_TYPE_LGHT48B | CCCE_CHECK | CICE_CHECK)
+#define RSP_TYPE_R2 (RSP_TYPE_LGHT136 | CCCE_CHECK | CICE_NOCHECK)
+#define RSP_TYPE_R3 (RSP_TYPE_LGHT48 | CCCE_NOCHECK | CICE_NOCHECK)
+#define RSP_TYPE_R4 (RSP_TYPE_LGHT48 | CCCE_NOCHECK | CICE_NOCHECK)
+#define RSP_TYPE_R5 (RSP_TYPE_LGHT48 | CCCE_CHECK | CICE_CHECK)
+#define RSP_TYPE_R6 (RSP_TYPE_LGHT48 | CCCE_CHECK | CICE_CHECK)
+#define RSP_TYPE_R7 (RSP_TYPE_LGHT48 | CCCE_CHECK | CICE_CHECK)
+
+/* All supported commands */
+#define MMC_CMD0 (INDEX(0) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD1 (INDEX(1) | RSP_TYPE_R3 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD2 (INDEX(2) | RSP_TYPE_R2 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD3 (INDEX(3) | RSP_TYPE_R1 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_SDCMD3 (INDEX(3) | RSP_TYPE_R6 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD4 (INDEX(4) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD6 (INDEX(6) | RSP_TYPE_R1B | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD7_SELECT (INDEX(7) | RSP_TYPE_R1B | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD7_DESELECT (INDEX(7)| RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD8 (INDEX(8) | RSP_TYPE_R1 | DP_DATA | DDIR_READ)
+#define MMC_SDCMD8 (INDEX(8) | RSP_TYPE_R7 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD9 (INDEX(9) | RSP_TYPE_R2 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD12 (INDEX(12) | RSP_TYPE_R1B | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD13 (INDEX(13) | RSP_TYPE_R1 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD15 (INDEX(15) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD16 (INDEX(16) | RSP_TYPE_R1 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_CMD17 (INDEX(17) | RSP_TYPE_R1 | DP_DATA | DDIR_READ)
+#define MMC_CMD24 (INDEX(24) | RSP_TYPE_R1 | DP_DATA | DDIR_WRITE)
+#define MMC_ACMD6 (INDEX(6) | RSP_TYPE_R1 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_ACMD41 (INDEX(41) | RSP_TYPE_R3 | DP_NO_DATA | DDIR_WRITE)
+#define MMC_ACMD51 (INDEX(51) | RSP_TYPE_R1 | DP_DATA | DDIR_READ)
+#define MMC_CMD55 (INDEX(55) | RSP_TYPE_R1 | DP_NO_DATA | DDIR_WRITE)
+
+#define MMC_AC_CMD_RCA_MASK (unsigned int)(0xFFFF << 16)
+#define MMC_BC_CMD_DSR_MASK (unsigned int)(0xFFFF << 16)
+#define MMC_DSR_DEFAULT 0x0404
+#define SD_CMD8_CHECK_PATTERN 0xAA
+#define SD_CMD8_2_7_3_6_V_RANGE (0x01 << 8)
+
+/* Clock Configurations and Macros */
+
+#define MMC_CLOCK_REFERENCE 96
+#define MMC_RELATIVE_CARD_ADDRESS 0x1234
+#define MMC_INIT_SEQ_CLK (MMC_CLOCK_REFERENCE * 1000 / 80)
+#define MMC_400kHz_CLK (MMC_CLOCK_REFERENCE * 1000 / 400)
+#define CLKDR(r, f, u) ((((r)*100) / ((f)*(u))) + 1)
+#define CLKD(f, u) (CLKDR(MMC_CLOCK_REFERENCE, f, u))
+
+#define MMC_OCR_REG_ACCESS_MODE_MASK (0x3 << 29)
+#define MMC_OCR_REG_ACCESS_MODE_BYTE (0x0 << 29)
+#define MMC_OCR_REG_ACCESS_MODE_SECTOR (0x2 << 29)
+
+#define MMC_OCR_REG_HOST_CAPACITY_SUPPORT_MASK (0x1 << 30)
+#define MMC_OCR_REG_HOST_CAPACITY_SUPPORT_BYTE (0x0 << 30)
+#define MMC_OCR_REG_HOST_CAPACITY_SUPPORT_SECTOR (0x1 << 30)
+
+#define MMC_SD2_CSD_C_SIZE_LSB_MASK 0xFFFF
+#define MMC_SD2_CSD_C_SIZE_MSB_MASK 0x003F
+#define MMC_SD2_CSD_C_SIZE_MSB_OFFSET 16
+#define MMC_CSD_C_SIZE_LSB_MASK 0x0003
+#define MMC_CSD_C_SIZE_MSB_MASK 0x03FF
+#define MMC_CSD_C_SIZE_MSB_OFFSET 2
+
+#define MMC_CSD_TRAN_SPEED_UNIT_MASK (0x07 << 0)
+#define MMC_CSD_TRAN_SPEED_FACTOR_MASK (0x0F << 3)
+#define MMC_CSD_TRAN_SPEED_UNIT_100MHZ (0x3 << 0)
+#define MMC_CSD_TRAN_SPEED_FACTOR_1_0 (0x01 << 3)
+#define MMC_CSD_TRAN_SPEED_FACTOR_8_0 (0x0F << 3)
+
+typedef struct {
+ unsigned not_used:1;
+ unsigned crc:7;
+ unsigned ecc:2;
+ unsigned file_format:2;
+ unsigned tmp_write_protect:1;
+ unsigned perm_write_protect:1;
+ unsigned copy:1;
+ unsigned file_format_grp:1;
+ unsigned content_prot_app:1;
+ unsigned reserved_1:4;
+ unsigned write_bl_partial:1;
+ unsigned write_bl_len:4;
+ unsigned r2w_factor:3;
+ unsigned default_ecc:2;
+ unsigned wp_grp_enable:1;
+ unsigned wp_grp_size:5;
+ unsigned erase_grp_mult:5;
+ unsigned erase_grp_size:5;
+ unsigned c_size_mult:3;
+ unsigned vdd_w_curr_max:3;
+ unsigned vdd_w_curr_min:3;
+ unsigned vdd_r_curr_max:3;
+ unsigned vdd_r_curr_min:3;
+ unsigned c_size_lsb:2;
+ unsigned c_size_msb:10;
+ unsigned reserved_2:2;
+ unsigned dsr_imp:1;
+ unsigned read_blk_misalign:1;
+ unsigned write_blk_misalign:1;
+ unsigned read_bl_partial:1;
+ unsigned read_bl_len:4;
+ unsigned ccc:12;
+ unsigned tran_speed:8;
+ unsigned nsac:8;
+ unsigned taac:8;
+ unsigned reserved_3:2;
+ unsigned spec_vers:4;
+ unsigned csd_structure:2;
+} mmc_csd_reg_t;
+
+/* csd for sd2.0 */
+typedef struct {
+ unsigned not_used:1;
+ unsigned crc:7;
+ unsigned reserved_1:2;
+ unsigned file_format:2;
+ unsigned tmp_write_protect:1;
+ unsigned perm_write_protect:1;
+ unsigned copy:1;
+ unsigned file_format_grp:1;
+ unsigned reserved_2:5;
+ unsigned write_bl_partial:1;
+ unsigned write_bl_len:4;
+ unsigned r2w_factor:3;
+ unsigned reserved_3:2;
+ unsigned wp_grp_enable:1;
+ unsigned wp_grp_size:7;
+ unsigned sector_size:7;
+ unsigned erase_blk_len:1;
+ unsigned reserved_4:1;
+ unsigned c_size_lsb:16;
+ unsigned c_size_msb:6;
+ unsigned reserved_5:6;
+ unsigned dsr_imp:1;
+ unsigned read_blk_misalign:1;
+ unsigned write_blk_misalign:1;
+ unsigned read_bl_partial:1;
+ unsigned read_bl_len:4;
+ unsigned ccc:12;
+ unsigned tran_speed:8;
+ unsigned nsac:8;
+ unsigned taac:8;
+ unsigned reserved_6:6;
+ unsigned csd_structure:2;
+} mmc_sd2_csd_reg_t;
+
+/* extended csd - 512 bytes long */
+typedef struct {
+ unsigned char reserved_1[181];
+ unsigned char erasedmemorycontent;
+ unsigned char reserved_2;
+ unsigned char buswidthmode;
+ unsigned char reserved_3;
+ unsigned char highspeedinterfacetiming;
+ unsigned char reserved_4;
+ unsigned char powerclass;
+ unsigned char reserved_5;
+ unsigned char commandsetrevision;
+ unsigned char reserved_6;
+ unsigned char commandset;
+ unsigned char extendedcsdrevision;
+ unsigned char reserved_7;
+ unsigned char csdstructureversion;
+ unsigned char reserved_8;
+ unsigned char cardtype;
+ unsigned char reserved_9[3];
+ unsigned char powerclass_52mhz_1_95v;
+ unsigned char powerclass_26mhz_1_95v;
+ unsigned char powerclass_52mhz_3_6v;
+ unsigned char powerclass_26mhz_3_6v;
+ unsigned char reserved_10;
+ unsigned char minreadperf_4b_26mhz;
+ unsigned char minwriteperf_4b_26mhz;
+ unsigned char minreadperf_8b_26mhz_4b_52mhz;
+ unsigned char minwriteperf_8b_26mhz_4b_52mhz;
+ unsigned char minreadperf_8b_52mhz;
+ unsigned char minwriteperf_8b_52mhz;
+ unsigned char reserved_11;
+ unsigned int sectorcount;
+ unsigned char reserved_12[288];
+ unsigned char supportedcommandsets;
+ unsigned char reserved_13[7];
+} mmc_extended_csd_reg_t;
+
+/* mmc sd responce */
+typedef struct {
+ unsigned int ocr;
+} mmc_resp_r3;
+
+typedef struct {
+ unsigned short cardstatus;
+ unsigned short newpublishedrca;
+} mmc_resp_r6;
+
+typedef union {
+ unsigned int resp[4];
+ mmc_resp_r3 r3;
+ mmc_resp_r6 r6;
+ mmc_csd_reg_t Card_CSD;
+} mmc_resp_t;
+
+#endif /* MMC_H */
diff --git a/u-boot/drivers/mmc/omap_hsmmc.c b/u-boot/drivers/mmc/omap_hsmmc.c
new file mode 100644
index 0000000..6f2280a
--- /dev/null
+++ b/u-boot/drivers/mmc/omap_hsmmc.c
@@ -0,0 +1,471 @@
+/*
+ * (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 <asm/io.h>
+#include <asm/arch/mmc_host_def.h>
+
+/* If we fail after 1 second wait, something is really bad */
+#define MAX_RETRY_MS 1000
+
+static int mmc_read_data(hsmmc_t *mmc_base, char *buf, unsigned int size);
+static int mmc_write_data(hsmmc_t *mmc_base, const char *buf, unsigned int siz);
+static struct mmc hsmmc_dev[2];
+unsigned char mmc_board_init(hsmmc_t *mmc_base)
+{
+#if defined(CONFIG_TWL4030_POWER)
+ twl4030_power_mmc_init();
+#endif
+
+#if defined(CONFIG_OMAP34XX)
+ t2_t *t2_base = (t2_t *)T2_BASE;
+ struct prcm *prcm_base = (struct prcm *)PRCM_BASE;
+
+ writel(readl(&t2_base->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);
+
+ 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
+
+/* TODO add appropriate OMAP4 init - none currently necessary */
+
+ return 0;
+}
+
+void mmc_init_stream(hsmmc_t *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)
+{
+ hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
+ unsigned int reg_val;
+ unsigned int dsor;
+ ulong start;
+
+ mmc_board_init(mmc_base);
+
+ 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;
+}
+
+
+static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
+ unsigned int flags, mmc_stat;
+ ulong start;
+
+ start = get_timer(0);
+ while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
+ if (get_timer(0) - start > MAX_RETRY_MS) {
+ printf("%s: timedout waiting for cmddis!\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!\n", __func__);
+ 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);
+ 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)
+ 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(hsmmc_t *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 & 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(hsmmc_t *mmc_base, const char *buf, unsigned int size)
+{
+ unsigned int *input_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 & 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)
+{
+ hsmmc_t *mmc_base = (hsmmc_t *)mmc->priv;
+ unsigned int dsor = 0;
+ ulong start;
+
+ /* 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)
+{
+ struct mmc *mmc;
+
+ mmc = &hsmmc_dev[dev_index];
+
+ sprintf(mmc->name, "OMAP SD/MMC");
+ mmc->send_cmd = mmc_send_cmd;
+ mmc->set_ios = mmc_set_ios;
+ mmc->init = mmc_init_setup;
+
+ switch (dev_index) {
+ case 0:
+ mmc->priv = (hsmmc_t *)OMAP_HSMMC1_BASE;
+ break;
+ case 1:
+ mmc->priv = (hsmmc_t *)OMAP_HSMMC2_BASE;
+ break;
+ case 2:
+ mmc->priv = (hsmmc_t *)OMAP_HSMMC3_BASE;
+ break;
+ default:
+ mmc->priv = (hsmmc_t *)OMAP_HSMMC1_BASE;
+ return 1;
+ }
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+ mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ mmc->f_min = 400000;
+ mmc->f_max = 52000000;
+
+ mmc_register(mmc);
+
+ return 0;
+}
diff --git a/u-boot/drivers/mmc/pxa_mmc.c b/u-boot/drivers/mmc/pxa_mmc.c
new file mode 100644
index 0000000..48e21ef
--- /dev/null
+++ b/u-boot/drivers/mmc/pxa_mmc.c
@@ -0,0 +1,647 @@
+/*
+ * (C) Copyright 2003
+ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <mmc.h>
+#include <asm/errno.h>
+#include <asm/arch/hardware.h>
+#include <part.h>
+#include <asm/io.h>
+
+#include "pxa_mmc.h"
+
+extern int fat_register_device(block_dev_desc_t * dev_desc, int part_no);
+
+static block_dev_desc_t mmc_dev;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+ return ((block_dev_desc_t *) & mmc_dev);
+}
+
+/*
+ * FIXME needs to read cid and csd info to determine block size
+ * and other parameters
+ */
+static uchar mmc_buf[MMC_BLOCK_SIZE];
+static uchar spec_ver;
+static int mmc_ready = 0;
+static int wide = 0;
+
+static uint32_t *
+/****************************************************/
+mmc_cmd(ushort cmd, ushort argh, ushort argl, ushort cmdat)
+/****************************************************/
+{
+ static uint32_t resp[4], a, b, c;
+ ulong status;
+ int i;
+
+ debug("mmc_cmd %u 0x%04x 0x%04x 0x%04x\n", cmd, argh, argl,
+ cmdat | wide);
+ writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL);
+ writel(~MMC_I_MASK_CLK_IS_OFF, MMC_I_MASK);
+ while (!(readl(MMC_I_REG) & MMC_I_REG_CLK_IS_OFF))
+ ;
+ writel(cmd, MMC_CMD);
+ writel(argh, MMC_ARGH);
+ writel(argl, MMC_ARGL);
+ writel(cmdat | wide, MMC_CMDAT);
+ writel(~MMC_I_MASK_END_CMD_RES, MMC_I_MASK);
+ writel(MMC_STRPCL_START_CLK, MMC_STRPCL);
+ while (!(readl(MMC_I_REG) & MMC_I_REG_END_CMD_RES))
+ ;
+
+ status = readl(MMC_STAT);
+ debug("MMC status 0x%08x\n", status);
+ if (status & MMC_STAT_TIME_OUT_RESPONSE) {
+ return 0;
+ }
+
+ /* Linux says:
+ * Did I mention this is Sick. We always need to
+ * discard the upper 8 bits of the first 16-bit word.
+ */
+ a = (readl(MMC_RES) & 0xffff);
+ for (i = 0; i < 4; i++) {
+ b = (readl(MMC_RES) & 0xffff);
+ c = (readl(MMC_RES) & 0xffff);
+ resp[i] = (a << 24) | (b << 8) | (c >> 8);
+ a = c;
+ debug("MMC resp[%d] = %#08x\n", i, resp[i]);
+ }
+
+ return resp;
+}
+
+int
+/****************************************************/
+mmc_block_read(uchar * dst, ulong src, ulong len)
+/****************************************************/
+{
+ ushort argh, argl;
+ ulong status;
+
+ if (len == 0) {
+ return 0;
+ }
+
+ debug("mmc_block_rd dst %lx src %lx len %d\n", (ulong) dst, src, len);
+
+ argh = len >> 16;
+ argl = len & 0xffff;
+
+ /* set block len */
+ mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
+
+ /* send read command */
+ argh = src >> 16;
+ argl = src & 0xffff;
+ writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL);
+ writel(0xffff, MMC_RDTO);
+ writel(1, MMC_NOB);
+ writel(len, MMC_BLKLEN);
+ mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl,
+ MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK |
+ MMC_CMDAT_DATA_EN);
+
+ writel(~MMC_I_MASK_RXFIFO_RD_REQ, MMC_I_MASK);
+ while (len) {
+ if (readl(MMC_I_REG) & MMC_I_REG_RXFIFO_RD_REQ) {
+#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
+ int i;
+ for (i = min(len, 32); i; i--) {
+ *dst++ = readb(MMC_RXFIFO);
+ len--;
+ }
+#else
+ *dst++ = readb(MMC_RXFIFO);
+ len--;
+#endif
+ }
+ status = readl(MMC_STAT);
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ }
+ writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK);
+ while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE))
+ ;
+ status = readl(MMC_STAT);
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ return 0;
+}
+
+int
+/****************************************************/
+mmc_block_write(ulong dst, uchar * src, int len)
+/****************************************************/
+{
+ ushort argh, argl;
+ ulong status;
+
+ if (len == 0) {
+ return 0;
+ }
+
+ debug("mmc_block_wr dst %lx src %lx len %d\n", dst, (ulong) src, len);
+
+ argh = len >> 16;
+ argl = len & 0xffff;
+
+ /* set block len */
+ mmc_cmd(MMC_CMD_SET_BLOCKLEN, argh, argl, MMC_CMDAT_R1);
+
+ /* send write command */
+ argh = dst >> 16;
+ argl = dst & 0xffff;
+ writel(MMC_STRPCL_STOP_CLK, MMC_STRPCL);
+ writel(1, MMC_NOB);
+ writel(len, MMC_BLKLEN);
+ mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, argh, argl,
+ MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK |
+ MMC_CMDAT_DATA_EN);
+
+ writel(~MMC_I_MASK_TXFIFO_WR_REQ, MMC_I_MASK);
+ while (len) {
+ if (readl(MMC_I_REG) & MMC_I_REG_TXFIFO_WR_REQ) {
+ int i, bytes = min(32, len);
+
+ for (i = 0; i < bytes; i++) {
+ writel(*src++, MMC_TXFIFO);
+ }
+ if (bytes < 32) {
+ writel(MMC_PRTBUF_BUF_PART_FULL, MMC_PRTBUF);
+ }
+ len -= bytes;
+ }
+ status = readl(MMC_STAT);
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ }
+ writel(~MMC_I_MASK_DATA_TRAN_DONE, MMC_I_MASK);
+ while (!(readl(MMC_I_REG) & MMC_I_REG_DATA_TRAN_DONE))
+ ;
+ writel(~MMC_I_MASK_PRG_DONE, MMC_I_MASK);
+ while (!(readl(MMC_I_REG) & MMC_I_REG_PRG_DONE))
+ ;
+ status = readl(MMC_STAT);
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ return 0;
+}
+
+int
+/****************************************************/
+pxa_mmc_read(long src, uchar * dst, int size)
+/****************************************************/
+{
+ ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
+ ulong mmc_block_size, mmc_block_address;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (!mmc_ready) {
+ printf("Please initial the MMC first\n");
+ return -1;
+ }
+
+ mmc_block_size = MMC_BLOCK_SIZE;
+ mmc_block_address = ~(mmc_block_size - 1);
+
+ src -= CONFIG_SYS_MMC_BASE;
+ end = src + size;
+ part_start = ~mmc_block_address & src;
+ part_end = ~mmc_block_address & end;
+ aligned_start = mmc_block_address & src;
+ aligned_end = mmc_block_address & end;
+
+ /* all block aligned accesses */
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if (part_start) {
+ part_len = mmc_block_size - part_start;
+ debug
+ ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <
+ 0) {
+ return -1;
+ }
+ memcpy(dst, mmc_buf + part_start, part_len);
+ dst += part_len;
+ src += part_len;
+ }
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ for (; src < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
+ debug
+ ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_read((uchar *) (dst), src, mmc_block_size)) < 0) {
+ return -1;
+ }
+ }
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if (part_end && src < end) {
+ debug
+ ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
+ return -1;
+ }
+ memcpy(dst, mmc_buf, part_end);
+ }
+ return 0;
+}
+
+int
+/****************************************************/
+pxa_mmc_write(uchar * src, ulong dst, int size)
+/****************************************************/
+{
+ ulong end, part_start, part_end, part_len, aligned_start, aligned_end;
+ ulong mmc_block_size, mmc_block_address;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (!mmc_ready) {
+ printf("Please initial the MMC first\n");
+ return -1;
+ }
+
+ mmc_block_size = MMC_BLOCK_SIZE;
+ mmc_block_address = ~(mmc_block_size - 1);
+
+ dst -= CONFIG_SYS_MMC_BASE;
+ end = dst + size;
+ part_start = ~mmc_block_address & dst;
+ part_end = ~mmc_block_address & end;
+ aligned_start = mmc_block_address & dst;
+ aligned_end = mmc_block_address & end;
+
+ /* all block aligned accesses */
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if (part_start) {
+ part_len = mmc_block_size - part_start;
+ debug
+ ("ps src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ (ulong) src, dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_read(mmc_buf, aligned_start, mmc_block_size)) <
+ 0) {
+ return -1;
+ }
+ memcpy(mmc_buf + part_start, src, part_len);
+ if ((mmc_block_write(aligned_start, mmc_buf, mmc_block_size)) <
+ 0) {
+ return -1;
+ }
+ dst += part_len;
+ src += part_len;
+ }
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ for (; dst < aligned_end; src += mmc_block_size, dst += mmc_block_size) {
+ debug
+ ("al src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_write(dst, (uchar *) src, mmc_block_size)) < 0) {
+ return -1;
+ }
+ }
+ debug
+ ("src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if (part_end && dst < end) {
+ debug
+ ("pe src %lx dst %lx end %lx pstart %lx pend %lx astart %lx aend %lx\n",
+ src, (ulong) dst, end, part_start, part_end, aligned_start,
+ aligned_end);
+ if ((mmc_block_read(mmc_buf, aligned_end, mmc_block_size)) < 0) {
+ return -1;
+ }
+ memcpy(mmc_buf, src, part_end);
+ if ((mmc_block_write(aligned_end, mmc_buf, mmc_block_size)) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static ulong
+/****************************************************/
+mmc_bread(int dev_num, ulong blknr, lbaint_t blkcnt, void *dst)
+/****************************************************/
+{
+ int mmc_block_size = MMC_BLOCK_SIZE;
+ ulong src = blknr * mmc_block_size + CONFIG_SYS_MMC_BASE;
+
+ pxa_mmc_read(src, (uchar *) dst, blkcnt * mmc_block_size);
+ return blkcnt;
+}
+
+#ifdef __GNUC__
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const uint32_t __mask = (__size < 32 ? 1 << __size : 0) - 1; \
+ const int32_t __off = 3 - ((start) / 32); \
+ const int32_t __shft = (start) & 31; \
+ uint32_t __res; \
+ \
+ __res = resp[__off] >> __shft; \
+ if (__size + __shft > 32) \
+ __res |= resp[__off-1] << ((32 - __shft) % 32); \
+ __res & __mask; \
+ })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(uint32_t * resp)
+{
+ if (IF_TYPE_SD == mmc_dev.if_type) {
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ sprintf((char *)mmc_dev.vendor,
+ "Man %02x OEM %c%c \"%c%c%c%c%c\" Date %02u/%04u",
+ UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp, 112, 8),
+ UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp, 96, 8),
+ UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp, 80, 8),
+ UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp, 64, 8),
+ UNSTUFF_BITS(resp, 8, 4), UNSTUFF_BITS(resp, 12,
+ 8) + 2000);
+ sprintf((char *)mmc_dev.revision, "%d.%d",
+ UNSTUFF_BITS(resp, 60, 4), UNSTUFF_BITS(resp, 56, 4));
+ sprintf((char *)mmc_dev.product, "%u",
+ UNSTUFF_BITS(resp, 24, 32));
+ } else {
+ /*
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
+ */
+ switch (spec_ver) {
+ case 0: /* MMC v1.0 - v1.2 */
+ case 1: /* MMC v1.4 */
+ sprintf((char *)mmc_dev.vendor,
+ "Man %02x%02x%02x \"%c%c%c%c%c%c%c\" Date %02u/%04u",
+ UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp,
+ 112,
+ 8),
+ UNSTUFF_BITS(resp, 104, 8), UNSTUFF_BITS(resp,
+ 96, 8),
+ UNSTUFF_BITS(resp, 88, 8), UNSTUFF_BITS(resp,
+ 80, 8),
+ UNSTUFF_BITS(resp, 72, 8), UNSTUFF_BITS(resp,
+ 64, 8),
+ UNSTUFF_BITS(resp, 56, 8), UNSTUFF_BITS(resp,
+ 48, 8),
+ UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8,
+ 4) +
+ 1997);
+ sprintf((char *)mmc_dev.revision, "%d.%d",
+ UNSTUFF_BITS(resp, 44, 4), UNSTUFF_BITS(resp,
+ 40, 4));
+ sprintf((char *)mmc_dev.product, "%u",
+ UNSTUFF_BITS(resp, 16, 24));
+ break;
+
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ case 4: /* MMC v4 */
+ sprintf((char *)mmc_dev.vendor,
+ "Man %02x OEM %04x \"%c%c%c%c%c%c\" Date %02u/%04u",
+ UNSTUFF_BITS(resp, 120, 8), UNSTUFF_BITS(resp,
+ 104,
+ 16),
+ UNSTUFF_BITS(resp, 96, 8), UNSTUFF_BITS(resp,
+ 88, 8),
+ UNSTUFF_BITS(resp, 80, 8), UNSTUFF_BITS(resp,
+ 72, 8),
+ UNSTUFF_BITS(resp, 64, 8), UNSTUFF_BITS(resp,
+ 56, 8),
+ UNSTUFF_BITS(resp, 12, 4), UNSTUFF_BITS(resp, 8,
+ 4) +
+ 1997);
+ sprintf((char *)mmc_dev.product, "%u",
+ UNSTUFF_BITS(resp, 16, 32));
+ sprintf((char *)mmc_dev.revision, "N/A");
+ break;
+
+ default:
+ printf("MMC card has unknown MMCA version %d\n",
+ spec_ver);
+ break;
+ }
+ }
+ printf("%s card.\nVendor: %s\nProduct: %s\nRevision: %s\n",
+ (IF_TYPE_SD == mmc_dev.if_type) ? "SD" : "MMC", mmc_dev.vendor,
+ mmc_dev.product, mmc_dev.revision);
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static void mmc_decode_csd(uint32_t * resp)
+{
+ unsigned int mult, csd_struct;
+
+ if (IF_TYPE_SD == mmc_dev.if_type) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 0) {
+ printf("SD: unrecognised CSD structure version %d\n",
+ csd_struct);
+ return;
+ }
+ } else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
+ */
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 1 && csd_struct != 2) {
+ printf("MMC: unrecognised CSD structure version %d\n",
+ csd_struct);
+ return;
+ }
+
+ spec_ver = UNSTUFF_BITS(resp, 122, 4);
+ mmc_dev.if_type = IF_TYPE_MMC;
+ }
+
+ mult = 1 << (UNSTUFF_BITS(resp, 47, 3) + 2);
+ mmc_dev.lba = (1 + UNSTUFF_BITS(resp, 62, 12)) * mult;
+ mmc_dev.blksz = 1 << UNSTUFF_BITS(resp, 80, 4);
+
+ /* FIXME: The following just makes assumes that's the partition type -- should really read it */
+ mmc_dev.part_type = PART_TYPE_DOS;
+ mmc_dev.dev = 0;
+ mmc_dev.lun = 0;
+ mmc_dev.type = DEV_TYPE_HARDDISK;
+ mmc_dev.removable = 0;
+ mmc_dev.block_read = mmc_bread;
+
+ printf("Detected: %lu blocks of %lu bytes (%luMB) ",
+ mmc_dev.lba,
+ mmc_dev.blksz,
+ mmc_dev.lba * mmc_dev.blksz / (1024 * 1024));
+}
+
+int
+/****************************************************/
+mmc_legacy_init(int verbose)
+/****************************************************/
+{
+ int retries, rc = -ENODEV;
+ uint32_t cid_resp[4];
+ uint32_t *resp;
+ uint16_t rca = 0;
+
+ /* Reset device interface type */
+ mmc_dev.if_type = IF_TYPE_UNKNOWN;
+
+#if defined (CONFIG_LUBBOCK) || (defined (CONFIG_GUMSTIX) && !defined(CONFIG_PXA27X))
+ set_GPIO_mode(GPIO6_MMCCLK_MD);
+ set_GPIO_mode(GPIO8_MMCCS0_MD);
+#endif
+#ifdef CONFIG_CPU_MONAHANS /* pxa3xx */
+ writel(readl(CKENA) | CKENA_12_MMC0 | CKENA_13_MMC1, CKENA);
+#else /* pxa2xx */
+ writel(readl(CKEN) | CKEN12_MMC, CKEN); /* enable MMC unit clock */
+#endif
+ writel(MMC_CLKRT_0_3125MHZ, MMC_CLKRT);
+ writel(MMC_RES_TO_MAX, MMC_RESTO);
+ writel(MMC_SPI_DISABLE, MMC_SPI);
+
+ /* reset */
+ mmc_cmd(MMC_CMD_GO_IDLE_STATE, 0, 0, MMC_CMDAT_INIT | MMC_CMDAT_R0);
+ udelay(200000);
+ retries = 3;
+ while (retries--) {
+ resp = mmc_cmd(MMC_CMD_APP_CMD, 0, 0, MMC_CMDAT_R1);
+ if (!(resp[0] & 0x00000020)) { /* Card does not support APP_CMD */
+ debug("Card does not support APP_CMD\n");
+ break;
+ }
+
+ /* Select 3.2-3.3V and 3.3-3.4V */
+ resp = mmc_cmd(SD_CMD_APP_SEND_OP_COND, 0x0030, 0x0000,
+ MMC_CMDAT_R3 | (retries < 2 ? 0
+ : MMC_CMDAT_INIT));
+ if (resp[0] & 0x80000000) {
+ mmc_dev.if_type = IF_TYPE_SD;
+ debug("Detected SD card\n");
+ break;
+ }
+ udelay(200000);
+ }
+
+ if (retries <= 0 || !(IF_TYPE_SD == mmc_dev.if_type)) {
+ debug("Failed to detect SD Card, trying MMC\n");
+ resp =
+ mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000, MMC_CMDAT_R3);
+
+ retries = 10;
+ while (retries-- && resp && !(resp[0] & 0x80000000)) {
+ udelay(200000);
+ resp =
+ mmc_cmd(MMC_CMD_SEND_OP_COND, 0x00ff, 0x8000,
+ MMC_CMDAT_R3);
+ }
+ }
+
+ /* try to get card id */
+ resp =
+ mmc_cmd(MMC_CMD_ALL_SEND_CID, 0, 0, MMC_CMDAT_R2 | MMC_CMDAT_BUSY);
+ if (resp) {
+ memcpy(cid_resp, resp, sizeof(cid_resp));
+
+ /* MMC exists, get CSD too */
+ resp = mmc_cmd(MMC_CMD_SET_RELATIVE_ADDR, 0, 0, MMC_CMDAT_R1);
+ if (IF_TYPE_SD == mmc_dev.if_type)
+ rca = ((resp[0] & 0xffff0000) >> 16);
+ resp = mmc_cmd(MMC_CMD_SEND_CSD, rca, 0, MMC_CMDAT_R2);
+ if (resp) {
+ mmc_decode_csd(resp);
+ rc = 0;
+ mmc_ready = 1;
+ }
+
+ mmc_decode_cid(cid_resp);
+ }
+
+ writel(0, MMC_CLKRT); /* 20 MHz */
+ resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1);
+
+#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS)
+ if (IF_TYPE_SD == mmc_dev.if_type) {
+ resp = mmc_cmd(MMC_CMD_APP_CMD, rca, 0, MMC_CMDAT_R1);
+ resp = mmc_cmd(SD_CMD_APP_SET_BUS_WIDTH, 0, 2, MMC_CMDAT_R1);
+ wide = MMC_CMDAT_SD_4DAT;
+ }
+#endif
+
+ fat_register_device(&mmc_dev, 1); /* partitions start counting with 1 */
+
+ return rc;
+}
diff --git a/u-boot/drivers/mmc/pxa_mmc.h b/u-boot/drivers/mmc/pxa_mmc.h
new file mode 100644
index 0000000..6fa4268
--- /dev/null
+++ b/u-boot/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/u-boot/drivers/mmc/s5p_mmc.c b/u-boot/drivers/mmc/s5p_mmc.c
new file mode 100644
index 0000000..195b5be
--- /dev/null
+++ b/u-boot/drivers/mmc/s5p_mmc.c
@@ -0,0 +1,477 @@
+/*
+ * (C) Copyright 2009 SAMSUNG Electronics
+ * Minkyu Kang <mk7.kang@samsung.com>
+ * Jaehoon Chung <jh80.chung@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/arch/mmc.h>
+
+/* support 4 mmc hosts */
+struct mmc mmc_dev[4];
+struct mmc_host mmc_host[4];
+
+static inline struct s5p_mmc *s5p_get_base_mmc(int dev_index)
+{
+ unsigned long offset = dev_index * sizeof(struct s5p_mmc);
+ return (struct s5p_mmc *)(samsung_get_base_mmc() + offset);
+}
+
+static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data)
+{
+ unsigned char ctrl;
+
+ debug("data->dest: %08x\n", (u32)data->dest);
+ writel((u32)data->dest, &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 &= ~(3 << 3);
+ writeb(ctrl, &host->reg->hostctl);
+
+ /* We do not handle DMA boundaries, so set it to max (512 KiB) */
+ writew((7 << 12) | (512 << 0), &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;
+
+ /*
+ * 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 = (1 << 1) | (1 << 0);
+ if (data->blocks > 1)
+ mode |= (1 << 5);
+ if (data->flags & MMC_DATA_READ)
+ mode |= (1 << 4);
+
+ writew(mode, &host->reg->trnmod);
+}
+
+static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct mmc_host *host = (struct mmc_host *)mmc->priv;
+ int flags, i;
+ unsigned int timeout;
+ unsigned int mask;
+ unsigned int retry = 0x100000;
+
+ /* Wait max 10 ms */
+ timeout = 10;
+
+ /*
+ * PRNSTS
+ * CMDINHDAT[1] : Command Inhibit (DAT)
+ * CMDINHCMD[0] : Command Inhibit (CMD)
+ */
+ mask = (1 << 0);
+ if ((data != NULL) || (cmd->resp_type & MMC_RSP_BUSY))
+ mask |= (1 << 1);
+
+ /*
+ * We shouldn't wait for data inihibit for stop commands, even
+ * though they might use busy signaling
+ */
+ if (data)
+ mask &= ~(1 << 1);
+
+ while (readl(&host->reg->prnsts) & mask) {
+ if (timeout == 0) {
+ printf("%s: timeout error\n", __func__);
+ return -1;
+ }
+ timeout--;
+ udelay(1000);
+ }
+
+ if (data)
+ mmc_prepare_data(host, data);
+
+ 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 = 0;
+ else if (cmd->resp_type & MMC_RSP_136)
+ flags = (1 << 0);
+ else if (cmd->resp_type & MMC_RSP_BUSY)
+ flags = (3 << 0);
+ else
+ flags = (2 << 0);
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ flags |= (1 << 3);
+ if (cmd->resp_type & MMC_RSP_OPCODE)
+ flags |= (1 << 4);
+ if (data)
+ flags |= (1 << 5);
+
+ 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 & (1 << 0)) {
+ if (!data)
+ writel(mask, &host->reg->norintsts);
+ break;
+ }
+ }
+
+ if (i == retry) {
+ printf("%s: waiting for status update\n", __func__);
+ return TIMEOUT;
+ }
+
+ if (mask & (1 << 16)) {
+ /* Timeout Error */
+ debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx);
+ return TIMEOUT;
+ } else if (mask & (1 << 15)) {
+ /* Error Interrupt */
+ debug("error: %08x cmd %d\n", mask, cmd->cmdidx);
+ 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__);
+ 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) {
+ while (1) {
+ mask = readl(&host->reg->norintsts);
+
+ if (mask & (1 << 15)) {
+ /* Error Interrupt */
+ writel(mask, &host->reg->norintsts);
+ printf("%s: error during transfer: 0x%08x\n",
+ __func__, mask);
+ return -1;
+ } else if (mask & (1 << 3)) {
+ /* DMA Interrupt */
+ debug("DMA end\n");
+ break;
+ } else if (mask & (1 << 1)) {
+ /* Transfer Complete */
+ debug("r/w is done\n");
+ break;
+ }
+ }
+ writel(mask, &host->reg->norintsts);
+ }
+
+ udelay(1000);
+ return 0;
+}
+
+static void mmc_change_clock(struct mmc_host *host, uint clock)
+{
+ int div;
+ unsigned short clk;
+ unsigned long timeout;
+ unsigned long ctrl2;
+
+ /*
+ * SELBASECLK[5:4]
+ * 00/01 = HCLK
+ * 10 = EPLL
+ * 11 = XTI or XEXTCLK
+ */
+ ctrl2 = readl(&host->reg->control2);
+ ctrl2 &= ~(3 << 4);
+ ctrl2 |= (2 << 4);
+ writel(ctrl2, &host->reg->control2);
+
+ writew(0, &host->reg->clkcon);
+
+ /* XXX: we assume that clock is between 40MHz and 50MHz */
+ if (clock == 0)
+ goto out;
+ else if (clock <= 400000)
+ div = 0x100;
+ else if (clock <= 20000000)
+ div = 4;
+ else if (clock <= 26000000)
+ div = 2;
+ else
+ div = 1;
+ debug("div: %d\n", div);
+
+ div >>= 1;
+ /*
+ * CLKCON
+ * SELFREQ[15:8] : base clock divied by value
+ * ENSDCLK[2] : SD Clock Enable
+ * STBLINTCLK[1] : Internal Clock Stable
+ * ENINTCLK[0] : Internal Clock Enable
+ */
+ clk = (div << 8) | (1 << 0);
+ writew(clk, &host->reg->clkcon);
+
+ /* Wait max 10 ms */
+ timeout = 10;
+ while (!(readw(&host->reg->clkcon) & (1 << 1))) {
+ if (timeout == 0) {
+ printf("%s: timeout error\n", __func__);
+ return;
+ }
+ timeout--;
+ udelay(1000);
+ }
+
+ clk |= (1 << 2);
+ writew(clk, &host->reg->clkcon);
+
+out:
+ host->clock = clock;
+}
+
+static void mmc_set_ios(struct mmc *mmc)
+{
+ struct mmc_host *host = mmc->priv;
+ unsigned char ctrl;
+ unsigned long val;
+
+ debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
+
+ /*
+ * SELCLKPADDS[17:16]
+ * 00 = 2mA
+ * 01 = 4mA
+ * 10 = 7mA
+ * 11 = 9mA
+ */
+ writel(0x3 << 16, &host->reg->control4);
+
+ val = readl(&host->reg->control2);
+ val &= (0x3 << 4);
+
+ val |= (1 << 31) | /* write status clear async mode enable */
+ (1 << 30) | /* command conflict mask enable */
+ (1 << 14) | /* Feedback Clock Enable for Rx Clock */
+ (1 << 8); /* SDCLK hold enable */
+
+ writel(val, &host->reg->control2);
+
+ /*
+ * 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)
+ */
+ writel(0x8080, &host->reg->control3);
+
+ 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);
+
+ /*
+ * OUTEDGEINV[2]
+ * 1 = Riging edge output
+ * 0 = Falling edge output
+ */
+ ctrl &= ~(1 << 2);
+
+ writeb(ctrl, &host->reg->hostctl);
+}
+
+static void mmc_reset(struct mmc_host *host)
+{
+ unsigned int timeout;
+
+ /*
+ * RSTALL[0] : Software reset for all
+ * 1 = reset
+ * 0 = work
+ */
+ writeb((1 << 0), &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) & (1 << 0)) {
+ if (timeout == 0) {
+ printf("%s: timeout error\n", __func__);
+ return;
+ }
+ timeout--;
+ udelay(1000);
+ }
+}
+
+static int mmc_core_init(struct mmc *mmc)
+{
+ struct mmc_host *host = (struct mmc_host *)mmc->priv;
+ unsigned int mask;
+
+ mmc_reset(host);
+
+ host->version = readw(&host->reg->hcver);
+
+ /* 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
+ * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable
+ * [0] ENSTACMDCMPLT : Command Complete Status Enable
+ */
+ mask = readl(&host->reg->norintstsen);
+ mask &= ~(0xffff);
+ mask |= (1 << 5) | (1 << 4) | (1 << 1) | (1 << 0);
+ 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 |= (1 << 1);
+ writel(mask, &host->reg->norintsigen);
+
+ return 0;
+}
+
+static int s5p_mmc_initialize(int dev_index, int bus_width)
+{
+ struct mmc *mmc;
+
+ mmc = &mmc_dev[dev_index];
+
+ sprintf(mmc->name, "SAMSUNG SD/MMC");
+ mmc->priv = &mmc_host[dev_index];
+ mmc->send_cmd = mmc_send_cmd;
+ mmc->set_ios = mmc_set_ios;
+ mmc->init = mmc_core_init;
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+ if (bus_width == 8)
+ mmc->host_caps = MMC_MODE_8BIT;
+ else
+ mmc->host_caps = MMC_MODE_4BIT;
+ mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ mmc->f_min = 400000;
+ mmc->f_max = 52000000;
+
+ mmc_host[dev_index].clock = 0;
+ mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index);
+ mmc_register(mmc);
+
+ return 0;
+}
+
+int s5p_mmc_init(int dev_index, int bus_width)
+{
+ return s5p_mmc_initialize(dev_index, bus_width);
+}