summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/arm_pl180_mmci.c1
-rw-r--r--drivers/mmc/bcm2835_sdhci.c189
-rw-r--r--drivers/mmc/bfin_sdh.c69
-rw-r--r--drivers/mmc/davinci_mmc.c1
-rw-r--r--drivers/mmc/fsl_esdhc.c1
-rw-r--r--drivers/mmc/ftsdc010_esdhc.c1
-rw-r--r--drivers/mmc/gen_atmel_mci.c1
-rw-r--r--drivers/mmc/mmc.c29
-rw-r--r--drivers/mmc/mmc_spi.c1
-rw-r--r--drivers/mmc/mxcmmc.c1
-rw-r--r--drivers/mmc/mxsmmc.c21
-rw-r--r--drivers/mmc/omap_hsmmc.c107
-rw-r--r--drivers/mmc/sdhci.c1
-rw-r--r--drivers/mmc/sh_mmcif.c1
-rw-r--r--drivers/mmc/tegra_mmc.c227
16 files changed, 532 insertions, 120 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 65791aa..1d6faa2 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_MXS_MMC) += mxsmmc.o
COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
COBJS-$(CONFIG_SDHCI) += sdhci.o
+COBJS-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index af1380a..ab2e81e 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -377,6 +377,7 @@ int arm_pl180_mmci_init(struct pl180_mmc_host *host)
dev->set_ios = host_set_ios;
dev->init = mmc_host_reset;
dev->getcd = NULL;
+ dev->getwp = NULL;
dev->host_caps = host->caps;
dev->voltages = host->voltages;
dev->f_min = host->clock_min;
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
new file mode 100644
index 0000000..b0afc3c
--- /dev/null
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -0,0 +1,189 @@
+/*
+ * 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>
+
+/* 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(bcm_host->last_write) < bcm_host->twoticks_delay)
+ ;
+
+ writel(val, host->ioaddr + reg);
+ bcm_host->last_write = get_timer(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/drivers/mmc/bfin_sdh.c b/drivers/mmc/bfin_sdh.c
index 8d59d46..2631174 100644
--- a/drivers/mmc/bfin_sdh.c
+++ b/drivers/mmc/bfin_sdh.c
@@ -19,9 +19,7 @@
#include <asm/mach-common/bits/sdh.h>
#include <asm/mach-common/bits/dma.h>
-#if defined(__ADSPBF50x__) || defined(__ADSPBF51x__)
-# define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CONTROL
-# define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CONTROL
+#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
@@ -38,10 +36,21 @@
# 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__)
@@ -70,6 +79,9 @@ sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
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);
@@ -104,6 +116,12 @@ sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
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;
}
@@ -113,16 +131,19 @@ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data)
{
u16 data_ctl = 0;
u16 dma_cfg = 0;
- int ret = 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 | RESTART | WNR | DMAEN;
+ dma_cfg = WDSIZE_32 | PSIZE_32 | RESTART | WNR | DMAEN;
bfin_write_SDH_DATA_TIMER(-1);
@@ -137,7 +158,7 @@ static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data)
/* kick off transfer */
bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
- return ret;
+ return 0;
}
@@ -147,13 +168,23 @@ static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
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) {
- ret = sdh_setup_data(mmc, data);
do {
udelay(1);
status = bfin_read_SDH_STATUS();
@@ -208,10 +239,12 @@ static void bfin_sdh_set_ios(struct mmc *mmc)
if (mmc->bus_width == 4) {
cfg = bfin_read_SDH_CFG();
- cfg &= ~0x80;
- cfg |= 0x40;
+#ifndef RSI_BLKSZ
+ cfg &= ~PD_SDDAT3;
+#endif
+ cfg |= PUP_SDDAT3;
bfin_write_SDH_CFG(cfg);
- clk_ctl |= WIDE_BUS;
+ clk_ctl |= WIDE_BUS_4;
}
bfin_write_SDH_CLK_CTL(clk_ctl);
sdh_set_clk(mmc->clock);
@@ -220,20 +253,23 @@ static void bfin_sdh_set_ios(struct mmc *mmc)
static int bfin_sdh_init(struct mmc *mmc)
{
const unsigned short pins[] = PORTMUX_PINS;
- u16 pwr_ctl = 0;
+ int ret;
/* Initialize sdh controller */
- peripheral_request_list(pins, "bfin_sdh");
+ 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);
-
- pwr_ctl |= ROD_CTL;
- pwr_ctl |= PWR_ON;
- bfin_write_SDH_PWR_CTL(pwr_ctl);
+#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;
}
@@ -251,6 +287,7 @@ int bfin_mmc_init(bd_t *bis)
mmc->set_ios = bfin_sdh_set_ios;
mmc->init = bfin_sdh_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->host_caps = MMC_MODE_4BIT;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index ee8f261..e2379e3 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -388,6 +388,7 @@ int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)
mmc->set_ios = dmmc_set_ios;
mmc->init = dmmc_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->f_min = 200000;
mmc->f_max = 25000000;
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index b90f3e7..54b5363 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -552,6 +552,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
mmc->set_ios = esdhc_set_ios;
mmc->init = esdhc_init;
mmc->getcd = esdhc_getcd;
+ mmc->getwp = NULL;
voltage_caps = 0;
caps = regs->hostcapblt;
diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
index f1702fe..42f0e0c 100644
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ b/drivers/mmc/ftsdc010_esdhc.c
@@ -666,6 +666,7 @@ int ftsdc010_mmc_init(int dev_index)
mmc->set_ios = ftsdc010_set_ios;
mmc->init = ftsdc010_core_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index 67b2dbe..70a9f91 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -349,6 +349,7 @@ int atmel_mci_init(void *regs)
mmc->set_ios = mci_set_ios;
mmc->init = mci_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
/* need to be able to pass these in on a board by board basis */
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 72e8ce6..d732581 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -40,6 +40,27 @@
static struct list_head mmc_devices;
static int cur_dev_num = -1;
+int __weak board_mmc_getwp(struct mmc *mmc)
+{
+ return -1;
+}
+
+int mmc_getwp(struct mmc *mmc)
+{
+ int wp;
+
+ wp = board_mmc_getwp(mmc);
+
+ if (wp < 0) {
+ if (mmc->getwp)
+ wp = mmc->getwp(mmc);
+ else
+ wp = 0;
+ }
+
+ return wp;
+}
+
int __board_mmc_getcd(struct mmc *mmc) {
return -1;
}
@@ -675,8 +696,12 @@ int mmc_getcd(struct mmc *mmc)
cd = board_mmc_getcd(mmc);
- if ((cd < 0) && mmc->getcd)
- cd = mmc->getcd(mmc);
+ if (cd < 0) {
+ if (mmc->getcd)
+ cd = mmc->getcd(mmc);
+ else
+ cd = 1;
+ }
return cd;
}
diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c
index 11ba532..fe6a5a1 100644
--- a/drivers/mmc/mmc_spi.c
+++ b/drivers/mmc/mmc_spi.c
@@ -273,6 +273,7 @@ struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
mmc->set_ios = mmc_spi_set_ios;
mmc->init = mmc_spi_init_p;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->host_caps = MMC_MODE_SPI;
mmc->voltages = MMC_SPI_VOLTAGE;
diff --git a/drivers/mmc/mxcmmc.c b/drivers/mmc/mxcmmc.c
index d58c18b..4f99617 100644
--- a/drivers/mmc/mxcmmc.c
+++ b/drivers/mmc/mxcmmc.c
@@ -499,6 +499,7 @@ static int mxcmci_initialize(bd_t *bis)
mmc->set_ios = mxcmci_set_ios;
mmc->init = mxcmci_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->host_caps = MMC_MODE_4BIT;
host->base = (struct mxcmci_regs *)CONFIG_MXC_MCI_REGS_BASE;
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index a72f66c..a89660f 100644
--- a/drivers/mmc/mxsmmc.c
+++ b/drivers/mmc/mxsmmc.c
@@ -53,12 +53,6 @@ struct mxsmmc_priv {
struct mxs_dma_desc *desc;
};
-#if defined(CONFIG_MX23)
-static const unsigned int mxsmmc_id_offset = 1;
-#elif defined(CONFIG_MX28)
-static const unsigned int mxsmmc_id_offset = 0;
-#endif
-
#define MXSMMC_MAX_TIMEOUT 10000
#define MXSMMC_SMALL_TRANSFER 512
@@ -137,7 +131,7 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
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 + mxsmmc_id_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);
@@ -390,15 +384,9 @@ 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;
-#if defined(CONFIG_MX23)
- const unsigned int mxsmmc_max_id = 2;
- const unsigned int mxsmmc_clk_id = 0;
-#elif defined(CONFIG_MX28)
- const unsigned int mxsmmc_max_id = 4;
- const unsigned int mxsmmc_clk_id = id;
-#endif
+ const unsigned int mxsmmc_clk_id = mxs_ssp_clock_by_bus(id);
- if (id >= mxsmmc_max_id)
+ if (!mxs_ssp_bus_id_valid(id))
return -ENODEV;
mmc = malloc(sizeof(struct mmc));
@@ -418,7 +406,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
return -ENOMEM;
}
- ret = mxs_dma_init_channel(id + mxsmmc_id_offset);
+ ret = mxs_dma_init_channel(MXS_DMA_CHANNEL_AHB_APBH_SSP0 + id);
if (ret)
return ret;
@@ -432,6 +420,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int), int (*cd)(int))
mmc->set_ios = mxsmmc_set_ios;
mmc->init = mxsmmc_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
mmc->priv = priv;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index afd9b30..166744c 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -30,6 +30,7 @@
#include <twl4030.h>
#include <twl6030.h>
#include <twl6035.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/mmc_host_def.h>
#include <asm/arch/sys_proto.h>
@@ -38,30 +39,71 @@
#define SYSCTL_SRC (1 << 25)
#define SYSCTL_SRD (1 << 26)
+struct omap_hsmmc_data {
+ struct hsmmc *base_addr;
+ int cd_gpio;
+ int wp_gpio;
+};
+
/* If we fail after 1 second wait, something is really bad */
#define MAX_RETRY_MS 1000
static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
unsigned int siz);
-static struct mmc hsmmc_dev[2];
+static struct mmc hsmmc_dev[3];
+static struct omap_hsmmc_data hsmmc_dev_data[3];
+
+#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
+ (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
+static int omap_mmc_setup_gpio_in(int gpio, const char *label)
+{
+ if (!gpio_is_valid(gpio))
+ return -1;
+
+ if (gpio_request(gpio, label) < 0)
+ return -1;
+
+ if (gpio_direction_input(gpio) < 0)
+ return -1;
+
+ return gpio;
+}
+
+static int omap_mmc_getcd(struct mmc *mmc)
+{
+ int cd_gpio = ((struct omap_hsmmc_data *)mmc->priv)->cd_gpio;
+ return gpio_get_value(cd_gpio);
+}
+
+static int omap_mmc_getwp(struct mmc *mmc)
+{
+ int wp_gpio = ((struct omap_hsmmc_data *)mmc->priv)->wp_gpio;
+ return gpio_get_value(wp_gpio);
+}
+#else
+static inline int omap_mmc_setup_gpio_in(int gpio, const char *label)
+{
+ return -1;
+}
+
+#define omap_mmc_getcd NULL
+#define omap_mmc_getwp NULL
+#endif
#if defined(CONFIG_OMAP44XX) && defined(CONFIG_TWL6030_POWER)
static void omap4_vmmc_pbias_config(struct mmc *mmc)
{
u32 value = 0;
- struct omap_sys_ctrl_regs *const ctrl =
- (struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
-
- value = readl(&ctrl->control_pbiaslite);
+ value = readl((*ctrl)->control_pbiaslite);
value &= ~(MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ);
- writel(value, &ctrl->control_pbiaslite);
+ writel(value, (*ctrl)->control_pbiaslite);
/* set VMMC to 3V */
twl6030_power_mmc_init();
- value = readl(&ctrl->control_pbiaslite);
+ value = readl((*ctrl)->control_pbiaslite);
value |= MMC1_PBIASLITE_VMODE | MMC1_PBIASLITE_PWRDNZ | MMC1_PWRDNZ;
- writel(value, &ctrl->control_pbiaslite);
+ writel(value, (*ctrl)->control_pbiaslite);
}
#endif
@@ -69,26 +111,24 @@ static void omap4_vmmc_pbias_config(struct mmc *mmc)
static void omap5_pbias_config(struct mmc *mmc)
{
u32 value = 0;
- struct omap_sys_ctrl_regs *const ctrl =
- (struct omap_sys_ctrl_regs *) SYSCTRL_GENERAL_CORE_BASE;
- value = readl(&ctrl->control_pbias);
+ value = readl((*ctrl)->control_pbias);
value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
value |= SDCARD_BIAS_HIZ_MODE;
- writel(value, &ctrl->control_pbias);
+ writel(value, (*ctrl)->control_pbias);
twl6035_mmc1_poweron_ldo();
- value = readl(&ctrl->control_pbias);
+ value = readl((*ctrl)->control_pbias);
value &= ~SDCARD_BIAS_HIZ_MODE;
value |= SDCARD_PBIASLITE_VMODE | SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ;
- writel(value, &ctrl->control_pbias);
+ writel(value, (*ctrl)->control_pbias);
- value = readl(&ctrl->control_pbias);
+ value = readl((*ctrl)->control_pbias);
if (value & (1 << 23)) {
value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
value |= SDCARD_BIAS_HIZ_MODE;
- writel(value, &ctrl->control_pbias);
+ writel(value, (*ctrl)->control_pbias);
}
}
#endif
@@ -177,11 +217,12 @@ void mmc_init_stream(struct hsmmc *mmc_base)
static int mmc_init_setup(struct mmc *mmc)
{
- struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv;
+ 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,
@@ -262,10 +303,11 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
- struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv;
+ 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) {
@@ -489,10 +531,11 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
static void mmc_set_ios(struct mmc *mmc)
{
- struct hsmmc *mmc_base = (struct hsmmc *)mmc->priv;
+ 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:
@@ -540,36 +583,44 @@ static void mmc_set_ios(struct mmc *mmc)
writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
}
-int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max)
+int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
+ int wp_gpio)
{
- struct mmc *mmc;
-
- mmc = &hsmmc_dev[dev_index];
+ struct mmc *mmc = &hsmmc_dev[dev_index];
+ struct omap_hsmmc_data *priv_data = &hsmmc_dev_data[dev_index];
sprintf(mmc->name, "OMAP SD/MMC");
mmc->send_cmd = mmc_send_cmd;
mmc->set_ios = mmc_set_ios;
mmc->init = mmc_init_setup;
- mmc->getcd = NULL;
+ mmc->priv = priv_data;
switch (dev_index) {
case 0:
- mmc->priv = (struct hsmmc *)OMAP_HSMMC1_BASE;
+ priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
break;
#ifdef OMAP_HSMMC2_BASE
case 1:
- mmc->priv = (struct hsmmc *)OMAP_HSMMC2_BASE;
+ priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
break;
#endif
#ifdef OMAP_HSMMC3_BASE
case 2:
- mmc->priv = (struct hsmmc *)OMAP_HSMMC3_BASE;
+ priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC3_BASE;
break;
#endif
default:
- mmc->priv = (struct hsmmc *)OMAP_HSMMC1_BASE;
+ priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC1_BASE;
return 1;
}
+ priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd");
+ if (priv_data->cd_gpio != -1)
+ mmc->getcd = omap_mmc_getcd;
+
+ priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp");
+ if (priv_data->wp_gpio != -1)
+ mmc->getwp = omap_mmc_getwp;
+
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS |
MMC_MODE_HC) & ~host_caps_mask;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 551b423..1eaea04 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -440,6 +440,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
mmc->set_ios = sdhci_set_ios;
mmc->init = sdhci_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
#ifdef CONFIG_MMC_SDMA
diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c
index 4588568..011d4f3 100644
--- a/drivers/mmc/sh_mmcif.c
+++ b/drivers/mmc/sh_mmcif.c
@@ -599,6 +599,7 @@ int mmcif_mmc_init(void)
mmc->set_ios = sh_mmcif_set_ios;
mmc->init = sh_mmcif_init;
mmc->getcd = NULL;
+ mmc->getwp = NULL;
host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
host->clk = CONFIG_SH_MMCIF_CLK;
mmc->priv = host;
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index d749ab0..e86bc68 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -2,7 +2,7 @@
* (C) Copyright 2009 SAMSUNG Electronics
* Minkyu Kang <mk7.kang@samsung.com>
* Jaehoon Chung <jh80.chung@samsung.com>
- * Portions Copyright 2011-2012 NVIDIA Corporation
+ * Portions Copyright 2011-2013 NVIDIA Corporation
*
* 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
@@ -28,43 +28,45 @@
#include <asm/arch-tegra/tegra_mmc.h>
#include <mmc.h>
-/* support 4 mmc hosts */
-struct mmc mmc_dev[4];
-struct mmc_host mmc_host[4];
+DECLARE_GLOBAL_DATA_PTR;
+struct mmc mmc_dev[MAX_HOSTS];
+struct mmc_host mmc_host[MAX_HOSTS];
-/**
- * Get the host address and peripheral ID for a device. Devices are numbered
- * from 0 to 3.
- *
- * @param host Structure to fill in (base, reg, mmc_id)
- * @param dev_index Device index (0-3)
- */
-static void tegra_get_setup(struct mmc_host *host, int dev_index)
+#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)
{
- debug("tegra_get_setup: dev_index = %d\n", dev_index);
-
- switch (dev_index) {
- case 1:
- host->base = TEGRA_SDMMC3_BASE;
- host->mmc_id = PERIPH_ID_SDMMC3;
- break;
- case 2:
- host->base = TEGRA_SDMMC2_BASE;
- host->mmc_id = PERIPH_ID_SDMMC2;
- break;
- case 3:
- host->base = TEGRA_SDMMC1_BASE;
- host->mmc_id = PERIPH_ID_SDMMC1;
- break;
- case 0:
- default:
- host->base = TEGRA_SDMMC4_BASE;
- host->mmc_id = PERIPH_ID_SDMMC4;
- break;
+ 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);
- host->reg = (struct tegra_mmc *)host->base;
+ /* 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,
@@ -363,8 +365,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)
debug(" mmc_change_clock called\n");
/*
- * Change Tegra SDMMCx clock divisor here. Source is 216MHz,
- * PLLP_OUT0
+ * Change Tegra SDMMCx clock divisor here. Source is PLLP_OUT0
*/
if (clock == 0)
goto out;
@@ -439,7 +440,7 @@ static void mmc_set_ios(struct mmc *mmc)
debug("mmc_set_ios: hostctl = %08X\n", ctrl);
}
-static void mmc_reset(struct mmc_host *host)
+static void mmc_reset(struct mmc_host *host, struct mmc *mmc)
{
unsigned int timeout;
debug(" mmc_reset called\n");
@@ -465,6 +466,14 @@ static void mmc_reset(struct mmc_host *host)
timeout--;
udelay(1000);
}
+
+ /* Set SD bus voltage & enable bus power */
+ mmc_set_power(host, fls(mmc->voltages) - 1);
+ debug("%s: power control = %02X, host control = %02X\n", __func__,
+ readb(&host->reg->pwrcon), readb(&host->reg->hostctl));
+
+ /* Make sure SDIO pads are set up */
+ pad_init_mmc(host);
}
static int mmc_core_init(struct mmc *mmc)
@@ -473,7 +482,7 @@ static int mmc_core_init(struct mmc *mmc)
unsigned int mask;
debug(" mmc_core_init called\n");
- mmc_reset(host);
+ mmc_reset(host, mmc);
host->version = readw(&host->reg->hcver);
debug("host version = %x\n", host->version);
@@ -518,41 +527,43 @@ int tegra_mmc_getcd(struct mmc *mmc)
debug("tegra_mmc_getcd called\n");
- if (host->cd_gpio >= 0)
- return !gpio_get_value(host->cd_gpio);
+ if (fdt_gpio_isvalid(&host->cd_gpio))
+ return fdtdec_get_gpio(&host->cd_gpio);
return 1;
}
-int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
+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;
- debug(" tegra_mmc_init: index %d, bus width %d "
- "pwr_gpio %d cd_gpio %d\n",
- dev_index, bus_width, pwr_gpio, cd_gpio);
-
+ /* DT should have been read & host config filled in */
host = &mmc_host[dev_index];
+ if (!host->enabled)
+ return -1;
- host->clock = 0;
- host->pwr_gpio = pwr_gpio;
- host->cd_gpio = cd_gpio;
- tegra_get_setup(host, dev_index);
+ 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 (host->pwr_gpio >= 0) {
+ if (fdt_gpio_isvalid(&host->pwr_gpio)) {
sprintf(gpusage, "SD/MMC%d PWR", dev_index);
- gpio_request(host->pwr_gpio, gpusage);
- gpio_direction_output(host->pwr_gpio, 1);
+ 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 (host->cd_gpio >= 0) {
+ if (fdt_gpio_isvalid(&host->cd_gpio)) {
sprintf(gpusage, "SD/MMC%d CD", dev_index);
- gpio_request(host->cd_gpio, gpusage);
- gpio_direction_input(host->cd_gpio);
+ gpio_request(host->cd_gpio.gpio, gpusage);
+ gpio_direction_input(host->cd_gpio.gpio);
+ debug(" CD GPIO name = %s\n", host->cd_gpio.name);
}
mmc = &mmc_dev[dev_index];
@@ -563,12 +574,13 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
mmc->set_ios = mmc_set_ios;
mmc->init = mmc_core_init;
mmc->getcd = tegra_mmc_getcd;
+ mmc->getwp = NULL;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
mmc->host_caps = 0;
- if (bus_width == 8)
+ if (host->width == 8)
mmc->host_caps |= MMC_MODE_8BIT;
- if (bus_width >= 4)
+ if (host->width >= 4)
mmc->host_caps |= MMC_MODE_4BIT;
mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC;
@@ -577,8 +589,6 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
* low-speed SDIO card frequency (actually 400KHz)
* max freq is highest HS eMMC clock as per the SD/MMC spec
* (actually 52MHz)
- * Both of these are the closest equivalents w/216MHz source
- * clock and Tegra SDMMC divisors.
*/
mmc->f_min = 375000;
mmc->f_max = 48000000;
@@ -587,3 +597,104 @@ int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
return 0;
}
+
+/**
+ * Get the host address and peripheral ID for a node.
+ *
+ * @param blob fdt blob
+ * @param node Device index (0-3)
+ * @param host Structure to fill in (reg, width, mmc_id)
+ */
+static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
+{
+ debug("%s: node = %d\n", __func__, node);
+
+ host->enabled = fdtdec_get_is_enabled(blob, node);
+
+ host->reg = (struct tegra_mmc *)fdtdec_get_addr(blob, node, "reg");
+ if ((fdt_addr_t)host->reg == FDT_ADDR_T_NONE) {
+ debug("%s: no sdmmc base reg info found\n", __func__);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ host->mmc_id = clock_decode_periph_id(blob, node);
+ if (host->mmc_id == PERIPH_ID_NONE) {
+ debug("%s: could not decode periph id\n", __func__);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /*
+ * NOTE: mmc->bus_width is determined by mmc.c dynamically.
+ * TBD: Override it with this value?
+ */
+ host->width = fdtdec_get_int(blob, node, "bus-width", 0);
+ if (!host->width)
+ debug("%s: no sdmmc width found\n", __func__);
+
+ /* These GPIOs are optional */
+ fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+ fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
+ fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
+
+ debug("%s: found controller at %p, width = %d, periph_id = %d\n",
+ __func__, host->reg, host->width, host->mmc_id);
+ return 0;
+}
+
+/*
+ * Process a list of nodes, adding them to our list of SDMMC ports.
+ *
+ * @param blob fdt blob
+ * @param node_list list of nodes to process (any <=0 are ignored)
+ * @param count number of nodes to process
+ * @return 0 if ok, -1 on error
+ */
+static int process_nodes(const void *blob, int node_list[], int count)
+{
+ struct mmc_host *host;
+ int i, node;
+
+ debug("%s: count = %d\n", __func__, count);
+
+ /* build mmc_host[] for each controller */
+ for (i = 0; i < count; i++) {
+ node = node_list[i];
+ if (node <= 0)
+ continue;
+
+ host = &mmc_host[i];
+ host->id = i;
+
+ if (mmc_get_config(blob, node, host)) {
+ printf("%s: failed to decode dev %d\n", __func__, i);
+ return -1;
+ }
+ do_mmc_init(i);
+ }
+ return 0;
+}
+
+void tegra_mmc_init(void)
+{
+ int node_list[MAX_HOSTS], count;
+ const void *blob = gd->fdt_blob;
+ debug("%s entry\n", __func__);
+
+ /* See if any Tegra30 MMC controllers are present */
+ count = fdtdec_find_aliases_for_id(blob, "sdhci",
+ COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS);
+ debug("%s: count of T30 sdhci nodes is %d\n", __func__, count);
+ if (process_nodes(blob, node_list, count)) {
+ printf("%s: Error processing T30 mmc node(s)!\n", __func__);
+ return;
+ }
+
+ /* Now look for any Tegra20 MMC controllers */
+ count = fdtdec_find_aliases_for_id(blob, "sdhci",
+ COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS);
+ debug("%s: count of T20 sdhci nodes is %d\n", __func__, count);
+ if (process_nodes(blob, node_list, count)) {
+ printf("%s: Error processing T20 mmc node(s)!\n", __func__);
+ return;
+ }
+}