aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot-sam460ex/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot-sam460ex/drivers/mmc')
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/Makefile52
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/atmel_mci.c533
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/atmel_mci.h201
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/bfin_sdh.c257
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/fsl_esdhc.c514
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/mmc.c945
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/mxcmmc.c522
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/omap3_mmc.c534
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.c646
-rw-r--r--roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.h138
10 files changed, 4342 insertions, 0 deletions
diff --git a/roms/u-boot-sam460ex/drivers/mmc/Makefile b/roms/u-boot-sam460ex/drivers/mmc/Makefile
new file mode 100644
index 000000000..6fa04b84f
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/Makefile
@@ -0,0 +1,52 @@
+#
+# (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.a
+
+COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
+COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o
+COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
+COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o
+COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
+COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o
+COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/roms/u-boot-sam460ex/drivers/mmc/atmel_mci.c b/roms/u-boot-sam460ex/drivers/mmc/atmel_mci.c
new file mode 100644
index 000000000..3946ffeeb
--- /dev/null
+++ b/roms/u-boot-sam460ex/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/roms/u-boot-sam460ex/drivers/mmc/atmel_mci.h b/roms/u-boot-sam460ex/drivers/mmc/atmel_mci.h
new file mode 100644
index 000000000..5b4f5c99b
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/atmel_mci.h
@@ -0,0 +1,201 @@
+/*
+ * 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__
+
+/* 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))
+
+/* 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/roms/u-boot-sam460ex/drivers/mmc/bfin_sdh.c b/roms/u-boot-sam460ex/drivers/mmc/bfin_sdh.c
new file mode 100644
index 000000000..f9d560a71
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/bfin_sdh.c
@@ -0,0 +1,257 @@
+/*
+ * 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/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
+#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
+#else
+# error no support for this proc yet
+#endif
+
+static int
+sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+ unsigned int sdh_cmd;
+ unsigned int status;
+ int cmd = mmc_cmd->cmdidx;
+ int flags = mmc_cmd->resp_type;
+ int arg = mmc_cmd->cmdarg;
+ int ret = 0;
+ sdh_cmd = 0;
+
+ sdh_cmd |= cmd;
+
+ 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 | CMD_E);
+
+ /* wait for a while */
+ do {
+ 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;
+
+ 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)
+{
+
+ u16 pwr_ctl = 0;
+/* Initialize sdh controller */
+#if defined(__ADSPBF54x__)
+ bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
+ bfin_write_PORTC_FER(bfin_read_PORTC_FER() | 0x3F00);
+ bfin_write_PORTC_MUX(bfin_read_PORTC_MUX() & ~0xFFF0000);
+#elif defined(__ADSPBF51x__)
+ bfin_write_PORTG_FER(bfin_read_PORTG_FER() | 0x01F8);
+ bfin_write_PORTG_MUX((bfin_read_PORTG_MUX() & ~0x3FC) | 0x154);
+#else
+# error no portmux for this proc yet
+#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/roms/u-boot-sam460ex/drivers/mmc/fsl_esdhc.c b/roms/u-boot-sam460ex/drivers/mmc/fsl_esdhc.c
new file mode 100644
index 000000000..a368fe60d
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/fsl_esdhc.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2007,2010 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;
+ }
+
+ 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;
+
+ 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;
+
+ 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;
+
+ /* Enable cache snooping */
+ if (cfg && !cfg->no_snoop)
+ esdhc_write32(&regs->scr, 0x00000040);
+
+ /* 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);
+
+ esdhc_write32(&regs->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
+
+ /* Set the initial clock speed */
+ set_sysctl(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;
+
+ 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;
+
+ caps = regs->hostcapblt;
+
+ if (caps & ESDHC_HOSTCAPBLT_VS18)
+ mmc->voltages |= MMC_VDD_165_195;
+ if (caps & ESDHC_HOSTCAPBLT_VS30)
+ mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+ if (caps & ESDHC_HOSTCAPBLT_VS33)
+ mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ 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, 50000000);
+
+ 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";
+ const char *status = "okay";
+
+ if (!hwconfig("esdhc")) {
+ status = "disabled";
+ goto out;
+ }
+
+ do_fixup_by_compat_u32(blob, compat, "clock-frequency",
+ gd->sdhc_clk, 1);
+out:
+ do_fixup_by_compat(blob, compat, "status", status,
+ strlen(status) + 1, 1);
+}
+#endif
diff --git a/roms/u-boot-sam460ex/drivers/mmc/mmc.c b/roms/u-boot-sam460ex/drivers/mmc/mmc.c
new file mode 100644
index 000000000..cf4ea161b
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/mmc.c
@@ -0,0 +1,945 @@
+/*
+ * 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_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+ int err;
+ int stoperr = 0;
+ struct mmc *mmc = find_mmc_device(dev_num);
+ int blklen;
+
+ if (!mmc)
+ return -1;
+
+ blklen = mmc->write_bl_len;
+
+ err = mmc_set_blocklen(mmc, mmc->write_bl_len);
+
+ if (err) {
+ printf("set write bl len failed\n\r");
+ return err;
+ }
+
+ 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 * blklen;
+
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.flags = 0;
+
+ data.src = src;
+ data.blocks = blkcnt;
+ data.blocksize = blklen;
+ data.flags = MMC_DATA_WRITE;
+
+ err = mmc_send_cmd(mmc, &cmd, &data);
+
+ if (err) {
+ printf("mmc write failed\n\r");
+ return err;
+ }
+
+ if (blkcnt > 1) {
+ cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.flags = 0;
+ stoperr = mmc_send_cmd(mmc, &cmd, NULL);
+ }
+
+ return blkcnt;
+}
+
+int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+
+ cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
+
+ if (mmc->high_capacity)
+ cmd.cmdarg = blocknum;
+ else
+ cmd.cmdarg = blocknum * mmc->read_bl_len;
+
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.flags = 0;
+
+ data.dest = dst;
+ data.blocks = 1;
+ data.blocksize = mmc->read_bl_len;
+ data.flags = MMC_DATA_READ;
+
+ return mmc_send_cmd(mmc, &cmd, &data);
+}
+
+int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size)
+{
+ char *buffer;
+ int i;
+ int blklen = mmc->read_bl_len;
+ int startblock = lldiv(src, mmc->read_bl_len);
+ int endblock = lldiv(src + size - 1, mmc->read_bl_len);
+ int err = 0;
+
+ /* Make a buffer big enough to hold all the blocks we might read */
+ buffer = malloc(blklen);
+
+ if (!buffer) {
+ printf("Could not allocate buffer for MMC read!\n");
+ return -1;
+ }
+
+ /* We always do full block reads from the card */
+ err = mmc_set_blocklen(mmc, mmc->read_bl_len);
+
+ if (err)
+ goto free_buffer;
+
+ for (i = startblock; i <= endblock; i++) {
+ int segment_size;
+ int offset;
+
+ err = mmc_read_block(mmc, buffer, i);
+
+ if (err)
+ goto free_buffer;
+
+ /*
+ * The first block may not be aligned, so we
+ * copy from the desired point in the block
+ */
+ offset = (src & (blklen - 1));
+ segment_size = MIN(blklen - offset, size);
+
+ memcpy(dst, buffer + offset, segment_size);
+
+ dst += segment_size;
+ src += segment_size;
+ size -= segment_size;
+ }
+
+free_buffer:
+ free(buffer);
+
+ return err;
+}
+
+static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
+{
+ int err;
+ int i;
+ struct mmc *mmc = find_mmc_device(dev_num);
+
+ if (!mmc)
+ return 0;
+
+ /* We always do full block reads from the card */
+ err = mmc_set_blocklen(mmc, mmc->read_bl_len);
+
+ if (err) {
+ return 0;
+ }
+
+ for (i = start; i < start + blkcnt; i++, dst += mmc->read_bl_len) {
+ err = mmc_read_block(mmc, dst, i);
+
+ if (err) {
+ printf("block read failed: %d\n", err);
+ return i - start;
+ }
+ }
+
+ 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;
+
+ /* 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))
+ 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/roms/u-boot-sam460ex/drivers/mmc/mxcmmc.c b/roms/u-boot-sam460ex/drivers/mmc/mxcmmc.c
new file mode 100644
index 000000000..59639539f
--- /dev/null
+++ b/roms/u-boot-sam460ex/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/roms/u-boot-sam460ex/drivers/mmc/omap3_mmc.c b/roms/u-boot-sam460ex/drivers/mmc/omap3_mmc.c
new file mode 100644
index 000000000..96c0e653b
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/omap3_mmc.c
@@ -0,0 +1,534 @@
+/*
+ * (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 <asm/arch/mmc.h>
+
+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)}
+};
+
+mmc_card_data cur_card_data;
+static block_dev_desc_t mmc_blk_dev;
+static hsmmc_t *mmc_base = (hsmmc_t *)OMAP_HSMMC_BASE;
+
+block_dev_desc_t *mmc_get_dev(int dev)
+{
+ return (block_dev_desc_t *) &mmc_blk_dev;
+}
+
+unsigned char mmc_board_init(void)
+{
+ t2_t *t2_base = (t2_t *)T2_BASE;
+
+#if defined(CONFIG_TWL4030_POWER)
+ twl4030_power_mmc_init();
+#endif
+
+ writel(readl(&t2_base->pbias_lite) | PBIASLITEPWRDNZ1 |
+ PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0,
+ &t2_base->pbias_lite);
+
+ writel(readl(&t2_base->devconf0) | MMCSDIO1ADPCLKISEL,
+ &t2_base->devconf0);
+
+ return 1;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+unsigned char omap_mmc_read_sect(unsigned int start_sec, unsigned int num_bytes,
+ mmc_card_data *mmc_c,
+ unsigned long *output_buf)
+{
+ unsigned char err;
+ unsigned int argument;
+ unsigned int resp[4];
+ unsigned int num_sec_val =
+ (num_bytes + (MMCSD_SECTOR_SIZE - 1)) / MMCSD_SECTOR_SIZE;
+ unsigned int sec_inc_val;
+
+ if (num_sec_val == 0)
+ return 1;
+
+ if (mmc_c->mode == SECTOR_MODE) {
+ argument = start_sec;
+ sec_inc_val = 1;
+ } else {
+ argument = start_sec * MMCSD_SECTOR_SIZE;
+ sec_inc_val = MMCSD_SECTOR_SIZE;
+ }
+
+ while (num_sec_val) {
+ err = mmc_send_cmd(MMC_CMD17, argument, resp);
+ if (err != 1)
+ return err;
+
+ err = mmc_read_data((unsigned int *) output_buf);
+ if (err != 1)
+ return err;
+
+ output_buf += (MMCSD_SECTOR_SIZE / 4);
+ argument += sec_inc_val;
+ num_sec_val--;
+ }
+ return 1;
+}
+
+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;
+}
+unsigned long mmc_bread(int dev_num, unsigned long blknr, lbaint_t blkcnt,
+ void *dst)
+{
+ omap_mmc_read_sect(blknr, (blkcnt * MMCSD_SECTOR_SIZE), &cur_card_data,
+ (unsigned long *) dst);
+ return 1;
+}
+
+int mmc_legacy_init(int verbose)
+{
+ 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/roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.c b/roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.c
new file mode 100644
index 000000000..8225235bf
--- /dev/null
+++ b/roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.c
@@ -0,0 +1,646 @@
+/*
+ * (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 "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);
+ MMC_STRPCL = MMC_STRPCL_STOP_CLK;
+ MMC_I_MASK = ~MMC_I_MASK_CLK_IS_OFF;
+ while (!(MMC_I_REG & MMC_I_REG_CLK_IS_OFF)) ;
+ MMC_CMD = cmd;
+ MMC_ARGH = argh;
+ MMC_ARGL = argl;
+ MMC_CMDAT = cmdat | wide;
+ MMC_I_MASK = ~MMC_I_MASK_END_CMD_RES;
+ MMC_STRPCL = MMC_STRPCL_START_CLK;
+ while (!(MMC_I_REG & MMC_I_REG_END_CMD_RES)) ;
+
+ status = 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 = (MMC_RES & 0xffff);
+ for (i = 0; i < 4; i++) {
+ b = (MMC_RES & 0xffff);
+ c = (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;
+ MMC_STRPCL = MMC_STRPCL_STOP_CLK;
+ MMC_RDTO = 0xffff;
+ MMC_NOB = 1;
+ MMC_BLKLEN = len;
+ mmc_cmd(MMC_CMD_READ_SINGLE_BLOCK, argh, argl,
+ MMC_CMDAT_R1 | MMC_CMDAT_READ | MMC_CMDAT_BLOCK |
+ MMC_CMDAT_DATA_EN);
+
+ MMC_I_MASK = ~MMC_I_MASK_RXFIFO_RD_REQ;
+ while (len) {
+ if (MMC_I_REG & MMC_I_REG_RXFIFO_RD_REQ) {
+#ifdef CONFIG_PXA27X
+ int i;
+ for (i = min(len, 32); i; i--) {
+ *dst++ = *((volatile uchar *)&MMC_RXFIFO);
+ len--;
+ }
+#else
+ *dst++ = MMC_RXFIFO;
+ len--;
+#endif
+ }
+ status = MMC_STAT;
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ }
+ MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
+ while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;
+ status = 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;
+ MMC_STRPCL = MMC_STRPCL_STOP_CLK;
+ MMC_NOB = 1;
+ MMC_BLKLEN = len;
+ mmc_cmd(MMC_CMD_WRITE_SINGLE_BLOCK, argh, argl,
+ MMC_CMDAT_R1 | MMC_CMDAT_WRITE | MMC_CMDAT_BLOCK |
+ MMC_CMDAT_DATA_EN);
+
+ MMC_I_MASK = ~MMC_I_MASK_TXFIFO_WR_REQ;
+ while (len) {
+ if (MMC_I_REG & MMC_I_REG_TXFIFO_WR_REQ) {
+ int i, bytes = min(32, len);
+
+ for (i = 0; i < bytes; i++) {
+ MMC_TXFIFO = *src++;
+ }
+ if (bytes < 32) {
+ MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL;
+ }
+ len -= bytes;
+ }
+ status = MMC_STAT;
+ if (status & MMC_STAT_ERRORS) {
+ printf("MMC_STAT error %lx\n", status);
+ return -1;
+ }
+ }
+ MMC_I_MASK = ~MMC_I_MASK_DATA_TRAN_DONE;
+ while (!(MMC_I_REG & MMC_I_REG_DATA_TRAN_DONE)) ;
+ MMC_I_MASK = ~MMC_I_MASK_PRG_DONE;
+ while (!(MMC_I_REG & MMC_I_REG_PRG_DONE)) ;
+ status = 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
+ CKEN |= CKEN12_MMC; /* enable MMC unit clock */
+
+ MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
+ MMC_RESTO = MMC_RES_TO_MAX;
+ MMC_SPI = MMC_SPI_DISABLE;
+
+ /* 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;
+ }
+#ifdef CONFIG_PXA27X
+ udelay(10000);
+#else
+ udelay(200000);
+#endif
+ }
+
+ 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)) {
+#ifdef CONFIG_PXA27X
+ udelay(10000);
+#else
+ udelay(200000);
+#endif
+ 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);
+ }
+
+ MMC_CLKRT = 0; /* 20 MHz */
+ resp = mmc_cmd(MMC_CMD_SELECT_CARD, rca, 0, MMC_CMDAT_R1);
+
+#ifdef CONFIG_PXA27X
+ 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/roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.h b/roms/u-boot-sam460ex/drivers/mmc/pxa_mmc.h
new file mode 100644
index 000000000..6fa42686e
--- /dev/null
+++ b/roms/u-boot-sam460ex/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__ */