diff options
| author | Kuo-Jung Su <dantesu@faraday-tech.com> | 2013-05-06 20:32:51 +0000 | 
|---|---|---|
| committer | Andy Fleming <afleming@freescale.com> | 2013-05-15 18:18:15 -0500 | 
| commit | f6c3b34697bf8bf05cb4e81c2fd3cadb9a98daea (patch) | |
| tree | 29a4d2080d2223f2e6b57a562cee7e66ea029a73 /drivers/mmc/ftsdc010_esdhc.c | |
| parent | fb651b10d43be36e7d7e16704c4b5ea1e295587a (diff) | |
| download | olio-uboot-2014.01-f6c3b34697bf8bf05cb4e81c2fd3cadb9a98daea.tar.xz olio-uboot-2014.01-f6c3b34697bf8bf05cb4e81c2fd3cadb9a98daea.zip | |
mmc: update Faraday FTSDC010 for rw performance
Faraday FTSDC010 is a MMC/SD host controller.
Although there is already a driver in current u-boot release,
which is modified from eSHDC and contributed by Andes Tech.
Its performance is too terrible on Faraday A36x SoC platforms,
so I turn to implement this new version of driver which is
10+ times faster than the old one.
It's carefully designed to be compatible with Andes chips,
so it should be safe to replace it.
Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Andy Fleming <afleming@gmail.com>
Signed-off-by: Andy Fleming <afleming@freescale.com>
Diffstat (limited to 'drivers/mmc/ftsdc010_esdhc.c')
| -rw-r--r-- | drivers/mmc/ftsdc010_esdhc.c | 687 | 
1 files changed, 0 insertions, 687 deletions
| diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c deleted file mode 100644 index 42f0e0ce5..000000000 --- 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(®->int_mask); -	newmask |= imask; - -	writel(newmask, ®->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; -} |