summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Makefile6
-rw-r--r--drivers/mmc/davinci_mmc.c5
-rw-r--r--drivers/mmc/fsl_esdhc.c5
-rw-r--r--drivers/mmc/ftsdc010_esdhc.c687
-rw-r--r--drivers/mmc/ftsdc010_mci.c377
-rw-r--r--drivers/mmc/mmc.c137
-rw-r--r--drivers/mmc/mv_sdhci.c3
-rw-r--r--drivers/mmc/s5p_sdhci.c3
-rw-r--r--drivers/mmc/spear_sdhci.c44
-rw-r--r--drivers/mmc/spl_mmc.c137
10 files changed, 536 insertions, 868 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 7cd4281733..24648a2937 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -25,14 +25,11 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmmc.o
-ifdef CONFIG_SPL_BUILD
-COBJS-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
-endif
COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
-COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010) += ftsdc010_mci.o
COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
@@ -46,6 +43,7 @@ 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_SPEAR_SDHCI) += spear_sdhci.o
COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
COBJS-$(CONFIG_DWMMC) += dw_mmc.o
COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index e2379e326e..5aa218426f 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -285,8 +285,11 @@ dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
*/
if (bytes_left > fifo_bytes)
dmmc_wait_fifo_status(regs, 0x4a);
- else if (bytes_left == fifo_bytes)
+ 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);
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index e945c0a470..861f4b9d6c 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -178,7 +178,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
int timeout;
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
-#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
uint wml_value;
wml_value = data->blocksize/4;
@@ -601,8 +601,7 @@ int fsl_esdhc_mmc_init(bd_t *bis)
{
struct fsl_esdhc_cfg *cfg;
- cfg = malloc(sizeof(struct fsl_esdhc_cfg));
- memset(cfg, 0, sizeof(struct fsl_esdhc_cfg));
+ cfg = 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);
diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
deleted file mode 100644
index 42f0e0ce55..0000000000
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (C) 2011 Andes Technology Corporation
- * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.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; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <config.h>
-#include <common.h>
-#include <mmc.h>
-
-#include <asm/io.h>
-#include <faraday/ftsdc010.h>
-
-/*
- * supported mmc hosts
- * setting the number CONFIG_FTSDC010_NUMBER in your configuration file.
- */
-static struct mmc ftsdc010_dev[CONFIG_FTSDC010_NUMBER];
-static struct mmc_host ftsdc010_host[CONFIG_FTSDC010_NUMBER];
-
-static struct ftsdc010_mmc *ftsdc010_get_base_mmc(int dev_index)
-{
- return (struct ftsdc010_mmc *)CONFIG_FTSDC010_BASE + dev_index;
-}
-
-#ifdef DEBUG
-static void ftsdc010_dump_reg(struct mmc_host *host)
-{
- debug("cmd: %08x\n", readl(&host->reg->cmd));
- debug("argu: %08x\n", readl(&host->reg->argu));
- debug("rsp0: %08x\n", readl(&host->reg->rsp0));
- debug("rsp1: %08x\n", readl(&host->reg->rsp1));
- debug("rsp2: %08x\n", readl(&host->reg->rsp2));
- debug("rsp3: %08x\n", readl(&host->reg->rsp3));
- debug("rsp_cmd: %08x\n", readl(&host->reg->rsp_cmd));
- debug("dcr: %08x\n", readl(&host->reg->dcr));
- debug("dtr: %08x\n", readl(&host->reg->dtr));
- debug("dlr: %08x\n", readl(&host->reg->dlr));
- debug("status: %08x\n", readl(&host->reg->status));
- debug("clr: %08x\n", readl(&host->reg->clr));
- debug("int_mask: %08x\n", readl(&host->reg->int_mask));
- debug("pcr: %08x\n", readl(&host->reg->pcr));
- debug("ccr: %08x\n", readl(&host->reg->ccr));
- debug("bwr: %08x\n", readl(&host->reg->bwr));
- debug("dwr: %08x\n", readl(&host->reg->dwr));
- debug("feature: %08x\n", readl(&host->reg->feature));
- debug("rev: %08x\n", readl(&host->reg->rev));
-}
-#endif
-
-static unsigned int enable_imask(struct ftsdc010_mmc *reg, unsigned int imask)
-{
- unsigned int newmask;
-
- newmask = readl(&reg->int_mask);
- newmask |= imask;
-
- writel(newmask, &reg->int_mask);
-
- return newmask;
-}
-
-static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int size)
-{
- unsigned int fifo;
- unsigned int fifo_words;
- unsigned int *ptr;
- unsigned int status;
- unsigned int retry = 0;
-
- /* get_data_buffer */
- ptr = (unsigned int *)buf;
-
- while (size) {
- status = readl(&host->reg->status);
- debug("%s: size: %08x\n", __func__, size);
-
- if (status & FTSDC010_STATUS_FIFO_ORUN) {
-
- debug("%s: FIFO OVERRUN: sta: %08x\n",
- __func__, status);
-
- fifo = host->fifo_len > size ?
- size : host->fifo_len;
-
- size -= fifo;
-
- fifo_words = fifo >> 2;
-
- while (fifo_words--)
- *ptr++ = readl(&host->reg->dwr);
-
- /*
- * for adding some delays for SD card to put
- * data into FIFO again
- */
- udelay(4*FTSDC010_DELAY_UNIT);
-
-#ifdef CONFIG_FTSDC010_SDIO
- /* sdio allow non-power-of-2 blksz */
- if (fifo & 3) {
- unsigned int n = fifo & 3;
- unsigned int data = readl(&host->reg->dwr);
-
- unsigned char *p = (unsigned char *)ptr;
-
- while (n--) {
- *p++ = data;
- data >>= 8;
- }
- }
-#endif
- } else {
- udelay(1);
- if (++retry >= FTSDC010_PIO_RETRY) {
- debug("%s: PIO_RETRY timeout\n", __func__);
- return;
- }
- }
- }
-}
-
-static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
- unsigned int size)
-{
- unsigned int fifo;
- unsigned int *ptr;
- unsigned int status;
- unsigned int retry = 0;
-
- /* get data buffer */
- ptr = (unsigned int *)buf;
-
- while (size) {
- status = readl(&host->reg->status);
-
- if (status & FTSDC010_STATUS_FIFO_URUN) {
- fifo = host->fifo_len > size ?
- size : host->fifo_len;
-
- size -= fifo;
-
- fifo = (fifo + 3) >> 2;
-
- while (fifo--) {
- writel(*ptr, &host->reg->dwr);
- ptr++;
- }
- } else {
- udelay(1);
- if (++retry >= FTSDC010_PIO_RETRY) {
- debug("%s: PIO_RETRY timeout\n", __func__);
- return;
- }
- }
- }
-}
-
-static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta, clear;
-
- sta = readl(&host->reg->status);
- debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
- /* check RSP TIMEOUT or FAIL */
- if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
- /* RSP TIMEOUT */
- debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_CLR_RSP_TIMEOUT;
- writel(clear, &host->reg->clr);
-
- return TIMEOUT;
- } else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
- /* clear response fail bit */
- debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_CLR_RSP_CRC_FAIL;
- writel(clear, &host->reg->clr);
-
- return COMM_ERR;
- } else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
-
- /* clear response CRC OK bit */
- clear |= FTSDC010_CLR_RSP_CRC_OK;
- }
-
- writel(clear, &host->reg->clr);
- return 0;
-}
-
-static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta, clear;
-
- sta = readl(&host->reg->status);
- debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
- /* check DATA TIMEOUT or FAIL */
- if (data) {
-
- /* Transfer Complete */
- if (sta & FTSDC010_STATUS_DATA_END)
- clear |= FTSDC010_STATUS_DATA_END;
-
- /* Data CRC_OK */
- if (sta & FTSDC010_STATUS_DATA_CRC_OK)
- clear |= FTSDC010_STATUS_DATA_CRC_OK;
-
- /* DATA TIMEOUT or DATA CRC FAIL */
- if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
- /* DATA TIMEOUT */
- debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_STATUS_DATA_TIMEOUT;
- writel(clear, &host->reg->clr);
-
- return TIMEOUT;
- } else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
- /* DATA CRC FAIL */
- debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
- writel(clear, &host->reg->clr);
-
- return COMM_ERR;
- }
- writel(clear, &host->reg->clr);
- }
- return 0;
-}
-
-static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
-
-#ifdef CONFIG_FTSDC010_SDIO
- unsigned int scon;
-#endif
- unsigned int ccon;
- unsigned int mask, tmpmask;
- unsigned int ret;
- unsigned int sta, i;
-
- ret = 0;
-
- if (data)
- mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
- else if (cmd->resp_type & MMC_RSP_PRESENT)
- mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
- else
- mask = FTSDC010_INT_MASK_CMD_SEND;
-
- /* write argu reg */
- debug("%s: argu: %08x\n", __func__, host->reg->argu);
- writel(cmd->cmdarg, &host->reg->argu);
-
- /* setup commnad */
- ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
-
- /* setup command flags */
- ccon |= FTSDC010_CMD_CMD_EN;
-
- /*
- * This hardware didn't support specific commands for mapping
- * MMC_RSP_BUSY and MMC_RSP_OPCODE. Hence we don't deal with it.
- */
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- ccon |= FTSDC010_CMD_NEED_RSP;
- mask |= FTSDC010_INT_MASK_RSP_CRC_OK |
- FTSDC010_INT_MASK_RSP_CRC_FAIL;
- }
-
- if (cmd->resp_type & MMC_RSP_136)
- ccon |= FTSDC010_CMD_LONG_RSP;
-
- /* In Linux driver, MMC_CMD_APP_CMD is checked in last_opcode */
- if (host->last_opcode == MMC_CMD_APP_CMD)
- ccon |= FTSDC010_CMD_APP_CMD;
-
-#ifdef CONFIG_FTSDC010_SDIO
- scon = readl(&host->reg->sdio_ctrl1);
- if (host->card_type == MMC_TYPE_SDIO)
- scon |= FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
- else
- scon &= ~FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
- writel(scon, &host->reg->sdio_ctrl1);
-#endif
-
- /* record last opcode for specifing the command type to hardware */
- host->last_opcode = cmd->cmdidx;
-
- /* write int_mask reg */
- tmpmask = readl(&host->reg->int_mask);
- tmpmask |= mask;
- writel(tmpmask, &host->reg->int_mask);
-
- /* write cmd reg */
- debug("%s: ccon: %08x\n", __func__, ccon);
- writel(ccon, &host->reg->cmd);
-
- /* check CMD_SEND */
- for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
- /*
- * If we read status register too fast
- * will lead hardware error and the RSP_TIMEOUT
- * flag will be raised incorrectly.
- */
- udelay(16*FTSDC010_DELAY_UNIT);
- sta = readl(&host->reg->status);
-
- /* Command Complete */
- /*
- * Note:
- * Do not clear FTSDC010_CLR_CMD_SEND flag.
- * (by writing FTSDC010_CLR_CMD_SEND bit to clear register)
- * It will make the driver becomes very slow.
- * If the operation hasn't been finished, hardware will
- * clear this bit automatically.
- * In origin, the driver will clear this flag if there is
- * no data need to be read.
- */
- if (sta & FTSDC010_STATUS_CMD_SEND)
- break;
- }
-
- if (i > FTSDC010_CMD_RETRY) {
- printf("%s: send command timeout\n", __func__);
- return TIMEOUT;
- }
-
- /* check rsp status */
- ret = ftsdc010_check_rsp(mmc, cmd, data);
- if (ret)
- return ret;
-
- /* read response if we have RSP_OK */
- if (ccon & FTSDC010_CMD_LONG_RSP) {
- cmd->response[0] = readl(&host->reg->rsp3);
- cmd->response[1] = readl(&host->reg->rsp2);
- cmd->response[2] = readl(&host->reg->rsp1);
- cmd->response[3] = readl(&host->reg->rsp0);
- } else {
- cmd->response[0] = readl(&host->reg->rsp0);
- }
-
- /* read/write data */
- if (data && (data->flags & MMC_DATA_READ)) {
- ftsdc010_pio_read(host, data->dest,
- data->blocksize * data->blocks);
- } else if (data && (data->flags & MMC_DATA_WRITE)) {
- ftsdc010_pio_write(host, data->src,
- data->blocksize * data->blocks);
- }
-
- /* check data status */
- if (data) {
- ret = ftsdc010_check_data(mmc, cmd, data);
- if (ret)
- return ret;
- }
-
- udelay(FTSDC010_DELAY_UNIT);
- return ret;
-}
-
-static unsigned int cal_blksz(unsigned int blksz)
-{
- unsigned int blksztwo = 0;
-
- while (blksz >>= 1)
- blksztwo++;
-
- return blksztwo;
-}
-
-static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int dcon, newmask;
-
- /* configure data transfer paramter */
- if (!data)
- return 0;
-
- if (((data->blocksize - 1) & data->blocksize) != 0) {
- printf("%s: can't do non-power-of 2 sized block transfers"
- " (blksz %d)\n", __func__, data->blocksize);
- return -1;
- }
-
- /*
- * We cannot deal with unaligned blocks with more than
- * one block being transfered.
- */
- if ((data->blocksize <= 2) && (data->blocks > 1)) {
- printf("%s: can't do non-word sized block transfers"
- " (blksz %d)\n", __func__, data->blocksize);
- return -1;
- }
-
- /* data length */
- dcon = data->blocksize * data->blocks;
- writel(dcon, &host->reg->dlr);
-
- /* write data control */
- dcon = cal_blksz(data->blocksize);
-
- /* add to IMASK register */
- newmask = (FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT);
-
- /*
- * enable UNDERRUN will trigger interrupt immediatedly
- * So setup it when rsp is received successfully
- */
- if (data->flags & MMC_DATA_WRITE) {
- dcon |= FTSDC010_DCR_DATA_WRITE;
- } else {
- dcon &= ~FTSDC010_DCR_DATA_WRITE;
- newmask |= FTSDC010_STATUS_FIFO_ORUN;
- }
- enable_imask(host->reg, newmask);
-
-#ifdef CONFIG_FTSDC010_SDIO
- /* always reset fifo since last transfer may fail */
- dcon |= FTSDC010_DCR_FIFO_RST;
-
- if (data->blocks > 1)
- dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
-#endif
-
- /* enable data transfer which will be pended until cmd is send */
- dcon |= FTSDC010_DCR_DATA_EN;
- writel(dcon, &host->reg->dcr);
-
- return 0;
-}
-
-static int ftsdc010_send_request(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- int ret;
-
- if (data) {
- ret = ftsdc010_setup_data(mmc, data);
-
- if (ret) {
- printf("%s: setup data error\n", __func__);
- return -1;
- }
-
- if ((data->flags & MMC_DATA_BOTH_DIR) == MMC_DATA_BOTH_DIR) {
- printf("%s: data is both direction\n", __func__);
- return -1;
- }
- }
-
- /* Send command */
- ret = ftsdc010_send_cmd(mmc, cmd, data);
- return ret;
-}
-
-static int ftsdc010_card_detect(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta;
-
- sta = readl(&host->reg->status);
- debug("%s: card status: %08x\n", __func__, sta);
-
- return (sta & FTSDC010_STATUS_CARD_DETECT) ? 0 : 1;
-}
-
-static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- int ret;
-
- if (ftsdc010_card_detect(mmc) == 0) {
- printf("%s: no medium present\n", __func__);
- return -1;
- } else {
- ret = ftsdc010_send_request(mmc, cmd, data);
- return ret;
- }
-}
-
-static void ftsdc010_set_clk(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned char clk_div;
- unsigned int real_rate;
- unsigned int clock;
-
- debug("%s: mmc_set_clock: %x\n", __func__, mmc->clock);
- clock = readl(&host->reg->ccr);
-
- if (mmc->clock == 0) {
- real_rate = 0;
- clock |= FTSDC010_CCR_CLK_DIS;
- } else {
- debug("%s, mmc->clock: %08x, origin clock: %08x\n",
- __func__, mmc->clock, clock);
-
- for (clk_div = 0; clk_div <= 127; clk_div++) {
- real_rate = (CONFIG_SYS_CLK_FREQ / 2) /
- (2 * (clk_div + 1));
-
- if (real_rate <= mmc->clock)
- break;
- }
-
- debug("%s: computed real_rate: %x, clk_div: %x\n",
- __func__, real_rate, clk_div);
-
- if (clk_div > 127)
- debug("%s: no match clock rate, %x\n",
- __func__, mmc->clock);
-
- clock = (clock & ~FTSDC010_CCR_CLK_DIV(0x7f)) |
- FTSDC010_CCR_CLK_DIV(clk_div);
-
- clock &= ~FTSDC010_CCR_CLK_DIS;
- }
-
- debug("%s, set clock: %08x\n", __func__, clock);
- writel(clock, &host->reg->ccr);
-}
-
-static void ftsdc010_set_ios(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int power;
- unsigned long val;
- unsigned int bus_width;
-
- debug("%s: bus_width: %x, clock: %d\n",
- __func__, mmc->bus_width, mmc->clock);
-
- /* set pcr: power on */
- power = readl(&host->reg->pcr);
- power |= FTSDC010_PCR_POWER_ON;
- writel(power, &host->reg->pcr);
-
- if (mmc->clock)
- ftsdc010_set_clk(mmc);
-
- /* set bwr: bus width reg */
- bus_width = readl(&host->reg->bwr);
- bus_width &= ~(FTSDC010_BWR_WIDE_8_BUS | FTSDC010_BWR_WIDE_4_BUS |
- FTSDC010_BWR_SINGLE_BUS);
-
- if (mmc->bus_width == 8)
- bus_width |= FTSDC010_BWR_WIDE_8_BUS;
- else if (mmc->bus_width == 4)
- bus_width |= FTSDC010_BWR_WIDE_4_BUS;
- else
- bus_width |= FTSDC010_BWR_SINGLE_BUS;
-
- writel(bus_width, &host->reg->bwr);
-
- /* set fifo depth */
- val = readl(&host->reg->feature);
- host->fifo_len = FTSDC010_FEATURE_FIFO_DEPTH(val) * 4; /* 4 bytes */
-
- /* set data timeout register */
- val = -1;
- writel(val, &host->reg->dtr);
-}
-
-static void ftsdc010_reset(struct mmc_host *host)
-{
- unsigned int timeout;
- unsigned int sta;
-
- /* Do SDC_RST: Software reset for all register */
- writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
-
- host->clock = 0;
-
- /* this hardware has no reset finish flag to read */
- /* wait 100ms maximum */
- timeout = 100;
-
- /* hw clears the bit when it's done */
- while (readl(&host->reg->dtr) != 0) {
- if (timeout == 0) {
- printf("%s: reset timeout error\n", __func__);
- return;
- }
- timeout--;
- udelay(10*FTSDC010_DELAY_UNIT);
- }
-
- sta = readl(&host->reg->status);
- if (sta & FTSDC010_STATUS_CARD_CHANGE)
- writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
-}
-
-static int ftsdc010_core_init(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int mask;
- unsigned int major, minor, revision;
-
- /* get hardware version */
- host->version = readl(&host->reg->rev);
-
- major = FTSDC010_REV_MAJOR(host->version);
- minor = FTSDC010_REV_MINOR(host->version);
- revision = FTSDC010_REV_REVISION(host->version);
-
- printf("ftsdc010 hardware ver: %d_%d_r%d\n", major, minor, revision);
-
- /* Interrupt MASK register init - mask all */
- writel(0x0, &host->reg->int_mask);
-
- mask = FTSDC010_INT_MASK_CMD_SEND |
- FTSDC010_INT_MASK_DATA_END |
- FTSDC010_INT_MASK_CARD_CHANGE;
-#ifdef CONFIG_FTSDC010_SDIO
- mask |= FTSDC010_INT_MASK_CP_READY |
- FTSDC010_INT_MASK_CP_BUF_READY |
- FTSDC010_INT_MASK_PLAIN_TEXT_READY |
- FTSDC010_INT_MASK_SDIO_IRPT;
-#endif
-
- writel(mask, &host->reg->int_mask);
-
- return 0;
-}
-
-int ftsdc010_mmc_init(int dev_index)
-{
- struct mmc *mmc;
- struct mmc_host *host;
-
- mmc = &ftsdc010_dev[dev_index];
-
- sprintf(mmc->name, "FTSDC010 SD/MMC");
- mmc->priv = &ftsdc010_host[dev_index];
- mmc->send_cmd = ftsdc010_request;
- 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;
-
- mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
-
- mmc->f_min = CONFIG_SYS_CLK_FREQ / 2 / (2*128);
- mmc->f_max = CONFIG_SYS_CLK_FREQ / 2 / 2;
-
- ftsdc010_host[dev_index].clock = 0;
- ftsdc010_host[dev_index].reg = ftsdc010_get_base_mmc(dev_index);
- mmc_register(mmc);
-
- /* reset mmc */
- host = (struct mmc_host *)mmc->priv;
- ftsdc010_reset(host);
-
- return 0;
-}
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000000..562b14aff8
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,377 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+
+struct ftsdc010_chip {
+ void __iomem *regs;
+ uint32_t wprot; /* write protected (locked) */
+ uint32_t rate; /* actual SD clock in Hz */
+ uint32_t sclk; /* FTSDC010 source clock in Hz */
+ uint32_t fifo; /* fifo depth in bytes */
+ uint32_t acmd;
+};
+
+static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ int ret = TIMEOUT;
+ uint32_t ts, st;
+ uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+ uint32_t arg = mmc_cmd->cmdarg;
+ uint32_t flags = mmc_cmd->resp_type;
+
+ cmd |= FTSDC010_CMD_CMD_EN;
+
+ if (chip->acmd) {
+ cmd |= FTSDC010_CMD_APP_CMD;
+ chip->acmd = 0;
+ }
+
+ if (flags & MMC_RSP_PRESENT)
+ cmd |= FTSDC010_CMD_NEED_RSP;
+
+ if (flags & MMC_RSP_136)
+ cmd |= FTSDC010_CMD_LONG_RSP;
+
+ writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+ &regs->clr);
+ writel(arg, &regs->argu);
+ writel(cmd, &regs->cmd);
+
+ if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+ writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+ ret = 0;
+ break;
+ }
+ }
+ } else {
+ st = 0;
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ st = readl(&regs->status);
+ writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+ if (st & FTSDC010_STATUS_RSP_MASK)
+ break;
+ }
+ if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+ if (flags & MMC_RSP_136) {
+ mmc_cmd->response[0] = readl(&regs->rsp3);
+ mmc_cmd->response[1] = readl(&regs->rsp2);
+ mmc_cmd->response[2] = readl(&regs->rsp1);
+ mmc_cmd->response[3] = readl(&regs->rsp0);
+ } else {
+ mmc_cmd->response[0] = readl(&regs->rsp0);
+ }
+ ret = 0;
+ } else {
+ debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+ mmc_cmd->cmdidx, st);
+ }
+ }
+
+ if (ret) {
+ debug("ftsdc010: cmd timeout (op code=%d)\n",
+ mmc_cmd->cmdidx);
+ } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+ chip->acmd = 1;
+ }
+
+ return ret;
+}
+
+static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ uint32_t div;
+
+ for (div = 0; div < 0x7f; ++div) {
+ if (rate >= chip->sclk / (2 * (div + 1)))
+ break;
+ }
+ chip->rate = chip->sclk / (2 * (div + 1));
+
+ writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+ if (IS_SD(mmc)) {
+ setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
+
+ if (chip->rate > 25000000)
+ setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+ else
+ clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+ }
+}
+
+static inline int ftsdc010_is_ro(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+ return chip->wprot || (csd[1] & 0x30);
+}
+
+static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
+{
+ int ret = TIMEOUT;
+ uint32_t st, ts;
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ st = readl(&regs->status);
+ if (!(st & mask))
+ continue;
+ writel(st & mask, &regs->clr);
+ ret = 0;
+ break;
+ }
+
+ if (ret)
+ debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+
+ return ret;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int ret = UNUSABLE_ERR;
+ uint32_t len = 0;
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+ if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+ printf("ftsdc010: the card is write protected!\n");
+ return ret;
+ }
+
+ if (data) {
+ uint32_t dcr;
+
+ len = data->blocksize * data->blocks;
+
+ /* 1. data disable + fifo reset */
+ writel(FTSDC010_DCR_FIFO_RST, &regs->dcr);
+
+ /* 2. clear status register */
+ writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+ | FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+ /* 3. data timeout (1 sec) */
+ writel(chip->rate, &regs->dtr);
+
+ /* 4. data length (bytes) */
+ writel(len, &regs->dlr);
+
+ /* 5. data enable */
+ dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+ if (data->flags & MMC_DATA_WRITE)
+ dcr |= FTSDC010_DCR_DATA_WRITE;
+ writel(dcr, &regs->dcr);
+ }
+
+ ret = ftsdc010_send_cmd(mmc, cmd);
+ if (ret) {
+ printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
+ return ret;
+ }
+
+ if (!data)
+ return ret;
+
+ if (data->flags & MMC_DATA_WRITE) {
+ const uint8_t *buf = (const uint8_t *)data->src;
+
+ while (len > 0) {
+ int wlen;
+
+ /* wait for tx ready */
+ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
+ if (ret)
+ break;
+
+ /* write bytes to ftsdc010 */
+ for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+ writel(*(uint32_t *)buf, &regs->dwr);
+ buf += 4;
+ wlen += 4;
+ }
+
+ len -= wlen;
+ }
+
+ } else {
+ uint8_t *buf = (uint8_t *)data->dest;
+
+ while (len > 0) {
+ int rlen;
+
+ /* wait for rx ready */
+ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
+ if (ret)
+ break;
+
+ /* fetch bytes from ftsdc010 */
+ for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+ *(uint32_t *)buf = readl(&regs->dwr);
+ buf += 4;
+ rlen += 4;
+ }
+
+ len -= rlen;
+ }
+
+ }
+
+ if (!ret) {
+ ret = ftsdc010_wait(regs,
+ FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+ }
+
+ return ret;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+ ftsdc010_clkset(mmc, mmc->clock);
+
+ clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
+ switch (mmc->bus_width) {
+ case 4:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
+ break;
+ case 8:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
+ break;
+ default:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
+ break;
+ }
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ uint32_t ts;
+
+ if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+ return NO_CARD_ERR;
+
+ if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+ printf("ftsdc010: write protected\n");
+ chip->wprot = 1;
+ }
+
+ chip->fifo = (readl(&regs->feature) & 0xff) << 2;
+
+ /* 1. chip reset */
+ writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
+ for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+ if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+ continue;
+ break;
+ }
+ if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
+ printf("ftsdc010: reset failed\n");
+ return UNUSABLE_ERR;
+ }
+
+ /* 2. enter low speed mode (400k card detection) */
+ ftsdc010_clkset(mmc, 400000);
+
+ /* 3. interrupt disabled */
+ writel(0, &regs->int_mask);
+
+ return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+ struct mmc *mmc;
+ struct ftsdc010_chip *chip;
+ struct ftsdc010_mmc __iomem *regs;
+#ifdef CONFIG_FTSDC010_BASE_LIST
+ uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
+
+ if (devid < 0 || devid >= ARRAY_SIZE(base_list))
+ return -1;
+ regs = (void __iomem *)base_list[devid];
+#else
+ regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
+#endif
+
+ mmc = malloc(sizeof(struct mmc));
+ if (!mmc)
+ return -ENOMEM;
+ memset(mmc, 0, sizeof(struct mmc));
+
+ chip = malloc(sizeof(struct ftsdc010_chip));
+ if (!chip) {
+ free(mmc);
+ return -ENOMEM;
+ }
+ memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+ chip->regs = regs;
+ mmc->priv = chip;
+
+ sprintf(mmc->name, "ftsdc010");
+ mmc->send_cmd = ftsdc010_request;
+ mmc->set_ios = ftsdc010_set_ios;
+ mmc->init = ftsdc010_init;
+
+ mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+ switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+ case FTSDC010_BWR_CAPS_4BIT:
+ mmc->host_caps |= MMC_MODE_4BIT;
+ break;
+ case FTSDC010_BWR_CAPS_8BIT:
+ mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+ break;
+ default:
+ break;
+ }
+
+#ifdef CONFIG_SYS_CLK_FREQ
+ chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+ chip->sclk = clk_get_rate("SDC");
+#endif
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->f_max = chip->sclk / 2;
+ mmc->f_min = chip->sclk / 0x100;
+ mmc->block_dev.part_type = PART_TYPE_DOS;
+
+ mmc_register(mmc);
+
+ return 0;
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 2590f1bcce..0a2f5358e2 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -524,48 +524,70 @@ static int sd_send_op_cond(struct mmc *mmc)
return 0;
}
-static int mmc_send_op_cond(struct mmc *mmc)
+/* 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 timeout = 10000;
- struct mmc_cmd cmd;
int err;
+ cmd->cmdidx = MMC_CMD_SEND_OP_COND;
+ cmd->resp_type = MMC_RSP_R3;
+ cmd->cmdarg = 0;
+ if (use_arg && !mmc_host_is_spi(mmc)) {
+ cmd->cmdarg =
+ (mmc->voltages &
+ (mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
+ (mmc->op_cond_response & OCR_ACCESS_MODE);
+
+ if (mmc->host_caps & MMC_MODE_HC)
+ cmd->cmdarg |= OCR_HCS;
+ }
+ err = mmc_send_cmd(mmc, cmd, NULL);
+ if (err)
+ return err;
+ mmc->op_cond_response = cmd->response[0];
+ return 0;
+}
+
+int mmc_send_op_cond(struct mmc *mmc)
+{
+ struct mmc_cmd cmd;
+ int err, i;
+
/* Some cards seem to need this */
mmc_go_idle(mmc);
/* Asking to the card its capabilities */
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ 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;
- 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;
+}
- udelay(1000);
+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 {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
- (mmc->voltages &
- (cmd.response[0] & OCR_VOLTAGE_MASK)) |
- (cmd.response[0] & OCR_ACCESS_MODE));
-
- if (mmc->host_caps & MMC_MODE_HC)
- cmd.cmdarg |= OCR_HCS;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
-
+ err = mmc_send_op_cond_iter(mmc, &cmd, 1);
if (err)
return err;
-
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
-
- if (timeout <= 0)
- return UNUSABLE_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;
@@ -1274,7 +1296,7 @@ block_dev_desc_t *mmc_get_dev(int dev)
}
#endif
-int mmc_init(struct mmc *mmc)
+int mmc_start_init(struct mmc *mmc)
{
int err;
@@ -1314,17 +1336,48 @@ int mmc_init(struct mmc *mmc)
if (err == TIMEOUT) {
err = mmc_send_op_cond(mmc);
- if (err) {
+ if (err && err != IN_PROGRESS) {
printf("Card did not respond to voltage select!\n");
return UNUSABLE_ERR;
}
}
- err = mmc_startup(mmc);
+ 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;
}
@@ -1362,6 +1415,25 @@ 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);
@@ -1372,5 +1444,6 @@ int mmc_initialize(bd_t *bis)
print_mmc_devices(',');
+ do_preinit();
return 0;
}
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index 2fe34b6993..63e1f9062b 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -51,6 +51,5 @@ int mv_sdh_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
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;
+ return add_sdhci(host, max_clk, min_clk);
}
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index dc49d37f5c..e50ff925a5 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -94,6 +94,5 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
host->host_caps = MMC_MODE_HC;
- add_sdhci(host, 52000000, 400000);
- return 0;
+ return add_sdhci(host, 52000000, 400000);
}
diff --git a/drivers/mmc/spear_sdhci.c b/drivers/mmc/spear_sdhci.c
new file mode 100644
index 0000000000..23f1f4b701
--- /dev/null
+++ b/drivers/mmc/spear_sdhci.c
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <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/drivers/mmc/spl_mmc.c b/drivers/mmc/spl_mmc.c
deleted file mode 100644
index 7efdcb88b7..0000000000
--- a/drivers/mmc/spl_mmc.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * (C) Copyright 2010
- * Texas Instruments, <www.ti.com>
- *
- * Aneesh V <aneesh@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; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <common.h>
-#include <spl.h>
-#include <asm/u-boot.h>
-#include <asm/utils.h>
-#include <mmc.h>
-#include <fat.h>
-#include <version.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static void mmc_load_image_raw(struct mmc *mmc)
-{
- unsigned long err;
- u32 image_size_sectors;
- struct image_header *header;
-
- header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
- sizeof(struct image_header));
-
- /* read image header to find the image size & load address */
- err = mmc->block_dev.block_read(0,
- CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, 1,
- header);
-
- if (err == 0)
- goto end;
-
- spl_parse_image_header(header);
-
- /* convert size to sectors - round up */
- image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) /
- mmc->read_bl_len;
-
- /* Read the header too to avoid extra memcpy */
- err = mmc->block_dev.block_read(0,
- CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
- image_size_sectors, (void *)spl_image.load_addr);
-
-end:
- if (err == 0) {
- printf("spl: mmc blk read err - %lu\n", err);
- hang();
- }
-}
-
-#ifdef CONFIG_SPL_FAT_SUPPORT
-static void mmc_load_image_fat(struct mmc *mmc)
-{
- int err;
- struct image_header *header;
-
- header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
- sizeof(struct image_header));
-
- err = fat_register_device(&mmc->block_dev,
- CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION);
- if (err) {
- printf("spl: fat register err - %d\n", err);
- hang();
- }
-
- err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME,
- header, sizeof(struct image_header));
- if (err <= 0)
- goto end;
-
- spl_parse_image_header(header);
-
- err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME,
- (u8 *)spl_image.load_addr, 0);
-
-end:
- if (err <= 0) {
- printf("spl: error reading image %s, err - %d\n",
- CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, err);
- hang();
- }
-}
-#endif
-
-void spl_mmc_load_image(void)
-{
- struct mmc *mmc;
- int err;
- u32 boot_mode;
-
- mmc_initialize(gd->bd);
- /* We register only one device. So, the dev id is always 0 */
- mmc = find_mmc_device(0);
- if (!mmc) {
- puts("spl: mmc device not found!!\n");
- hang();
- }
-
- err = mmc_init(mmc);
- if (err) {
- printf("spl: mmc init failed: err - %d\n", err);
- hang();
- }
- boot_mode = spl_boot_mode();
- if (boot_mode == MMCSD_MODE_RAW) {
- debug("boot mode - RAW\n");
- mmc_load_image_raw(mmc);
-#ifdef CONFIG_SPL_FAT_SUPPORT
- } else if (boot_mode == MMCSD_MODE_FAT) {
- debug("boot mode - FAT\n");
- mmc_load_image_fat(mmc);
-#endif
- } else {
- puts("spl: wrong MMC boot mode\n");
- hang();
- }
-}