diff options
| author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2013-05-30 14:45:06 +0200 | 
|---|---|---|
| committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2013-05-30 14:45:06 +0200 | 
| commit | a19b0dd62d7b8efc658fa1aa685ff5665878f3ee (patch) | |
| tree | 1fadf0fb3da83203ba28f209ec99e1b33e03f4d5 /drivers/mmc | |
| parent | 60985bba58e7695dac1fddae8cdbb62d8cfd1254 (diff) | |
| parent | a71d45d706a5b51c348160163b6c159632273fed (diff) | |
| download | olio-uboot-2014.01-a19b0dd62d7b8efc658fa1aa685ff5665878f3ee.tar.xz olio-uboot-2014.01-a19b0dd62d7b8efc658fa1aa685ff5665878f3ee.zip | |
Merge branch 'u-boot/master' into 'u-boot-arm/master'
Conflicts:
	common/cmd_fpga.c
	drivers/usb/host/ohci-at91.c
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/Makefile | 6 | ||||
| -rw-r--r-- | drivers/mmc/davinci_mmc.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/fsl_esdhc.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/ftsdc010_esdhc.c | 687 | ||||
| -rw-r--r-- | drivers/mmc/ftsdc010_mci.c | 377 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 137 | ||||
| -rw-r--r-- | drivers/mmc/mv_sdhci.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/s5p_sdhci.c | 3 | ||||
| -rw-r--r-- | drivers/mmc/spear_sdhci.c | 44 | ||||
| -rw-r--r-- | drivers/mmc/spl_mmc.c | 137 | 
10 files changed, 536 insertions, 868 deletions
| diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 7cd428173..24648a293 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 e2379e326..5aa218426 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(®s->mmcdrr); diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index e945c0a47..861f4b9d6 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 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; -} diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c new file mode 100644 index 000000000..562b14aff --- /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, +		®s->clr); +	writel(arg, ®s->argu); +	writel(cmd, ®s->cmd); + +	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) { +		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +			if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) { +				writel(FTSDC010_STATUS_CMD_SEND, ®s->clr); +				ret = 0; +				break; +			} +		} +	} else { +		st = 0; +		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +			st = readl(®s->status); +			writel(st & FTSDC010_STATUS_RSP_MASK, ®s->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(®s->rsp3); +				mmc_cmd->response[1] = readl(®s->rsp2); +				mmc_cmd->response[2] = readl(®s->rsp1); +				mmc_cmd->response[3] = readl(®s->rsp0); +			} else { +				mmc_cmd->response[0] = readl(®s->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), ®s->ccr); + +	if (IS_SD(mmc)) { +		setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD); + +		if (chip->rate > 25000000) +			setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); +		else +			clrbits_le32(®s->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(®s->status); +		if (!(st & mask)) +			continue; +		writel(st & mask, ®s->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, ®s->dcr); + +		/* 2. clear status register */ +		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN +			| FTSDC010_STATUS_FIFO_ORUN, ®s->clr); + +		/* 3. data timeout (1 sec) */ +		writel(chip->rate, ®s->dtr); + +		/* 4. data length (bytes) */ +		writel(len, ®s->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, ®s->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, ®s->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(®s->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(®s->bwr, FTSDC010_BWR_MODE_MASK); +	switch (mmc->bus_width) { +	case 4: +		setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT); +		break; +	case 8: +		setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT); +		break; +	default: +		setbits_le32(®s->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(®s->status) & FTSDC010_STATUS_CARD_DETECT) +		return NO_CARD_ERR; + +	if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { +		printf("ftsdc010: write protected\n"); +		chip->wprot = 1; +	} + +	chip->fifo = (readl(®s->feature) & 0xff) << 2; + +	/* 1. chip reset */ +	writel(FTSDC010_CMD_SDC_RST, ®s->cmd); +	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) { +		if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) +			continue; +		break; +	} +	if (readl(®s->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, ®s->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(®s->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 2590f1bcc..0a2f5358e 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 2fe34b699..63e1f9062 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 dc49d37f5..e50ff925a 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 000000000..23f1f4b70 --- /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 7efdcb88b..000000000 --- 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(); -	} -} |