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