diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/Makefile | 4 | ||||
| -rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 131 | ||||
| -rw-r--r-- | drivers/mmc/arm_pl180_mmci.h | 27 | ||||
| -rw-r--r-- | drivers/mmc/fsl_esdhc.c | 5 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 28 | ||||
| -rw-r--r-- | drivers/mmc/mxsmmc.c | 204 | ||||
| -rw-r--r-- | drivers/mmc/spl_mmc_load.c | 62 | ||||
| -rw-r--r-- | drivers/mmc/tegra_mmc.c | 32 | ||||
| -rw-r--r-- | drivers/mmc/tegra_mmc.h | 12 | 
9 files changed, 279 insertions, 226 deletions
| diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index c56773701..2b96cdcd4 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -25,6 +25,10 @@ include $(TOPDIR)/config.mk  LIB	:= $(obj)libmmc.o +ifdef CONFIG_SPL_MMC_LOAD +COBJS-$(CONFIG_SPL_MMC_LOAD)	+= spl_mmc_load.o +endif +  COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o  COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o  COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 09d443ee3..db2c7ab75 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -32,14 +32,10 @@  #include "arm_pl180_mmci.h"  #include <malloc.h> -struct mmc_host { -	struct sdi_registers *base; -}; -  static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)  {  	u32 hoststatus, statusmask; -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;  	if ((cmd->resp_type & MMC_RSP_PRESENT)) @@ -53,8 +49,8 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)  	writel(statusmask, &host->base->status_clear);  	if (hoststatus & SDI_STA_CTIMEOUT) { -		printf("CMD%d time out\n", cmd->cmdidx); -		return -ETIMEDOUT; +		debug("CMD%d time out\n", cmd->cmdidx); +		return TIMEOUT;  	} else if ((hoststatus & SDI_STA_CCRCFAIL) &&  		   (cmd->flags & MMC_RSP_CRC)) {  		printf("CMD%d CRC error\n", cmd->cmdidx); @@ -80,7 +76,7 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)  {  	int result;  	u32 sdi_cmd = 0; -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN); @@ -112,7 +108,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)  {  	u32 *tempbuff = dest;  	u64 xfercount = blkcount * blksize; -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	u32 status, status_err;  	debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -168,7 +164,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)  	u32 *tempbuff = src;  	int i;  	u64 xfercount = blkcount * blksize; -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	u32 status, status_err;  	debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -227,14 +223,19 @@ static int do_data_transfer(struct mmc *dev,  			    struct mmc_data *data)  {  	int error = -ETIMEDOUT; -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	u32 blksz = 0;  	u32 data_ctrl = 0;  	u32 data_len = (u32) (data->blocks * data->blocksize); -	blksz = (ffs(data->blocksize) - 1); -	data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); -	data_ctrl |= SDI_DCTRL_DTEN; +	if (!host->version2) { +		blksz = (ffs(data->blocksize) - 1); +		data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); +	} else { +		blksz = data->blocksize; +		data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT); +	} +	data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;  	writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);  	writel(data_len, &host->base->datalength); @@ -257,7 +258,7 @@ static int do_data_transfer(struct mmc *dev,  		writel(data_ctrl, &host->base->datactrl);  		error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks, -				    (u32)data->blocksize); +							(u32)data->blocksize);  	}  	return error; @@ -280,17 +281,16 @@ static int host_request(struct mmc *dev,  /* MMC uses open drain drivers in the enumeration phase */  static int mmc_host_reset(struct mmc *dev)  { -	struct mmc_host *host = dev->priv; -	u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; +	struct pl180_mmc_host *host = dev->priv; -	writel(sdi_u32, &host->base->power); +	writel(host->pwr_init, &host->base->power);  	return 0;  }  static void host_set_ios(struct mmc *dev)  { -	struct mmc_host *host = dev->priv; +	struct pl180_mmc_host *host = dev->priv;  	u32 sdi_clkcr;  	sdi_clkcr = readl(&host->base->clock); @@ -298,15 +298,26 @@ static void host_set_ios(struct mmc *dev)  	/* Ramp up the clock rate */  	if (dev->clock) {  		u32 clkdiv = 0; +		u32 tmp_clock; -		if (dev->clock >= dev->f_max) +		if (dev->clock >= dev->f_max) { +			clkdiv = 0;  			dev->clock = dev->f_max; +		} else { +			clkdiv = (host->clock_in / dev->clock) - 2; +		} -		clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1; +		tmp_clock = host->clock_in / (clkdiv + 2); +		while (tmp_clock > dev->clock) { +			clkdiv++; +			tmp_clock = host->clock_in / (clkdiv + 2); +		}  		if (clkdiv > SDI_CLKCR_CLKDIV_MASK)  			clkdiv = SDI_CLKCR_CLKDIV_MASK; +		tmp_clock = host->clock_in / (clkdiv + 2); +		dev->clock = tmp_clock;  		sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);  		sdi_clkcr |= clkdiv;  	} @@ -322,8 +333,11 @@ static void host_set_ios(struct mmc *dev)  		case 4:  			buswidth |= SDI_CLKCR_WIDBUS_4;  			break; +		case 8: +			buswidth |= SDI_CLKCR_WIDBUS_8; +			break;  		default: -			printf("Invalid bus width\n"); +			printf("Invalid bus width: %d\n", dev->bus_width);  			break;  		}  		sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); @@ -334,83 +348,40 @@ static void host_set_ios(struct mmc *dev)  	udelay(CLK_CHANGE_DELAY);  } -struct mmc *alloc_mmc_struct(void) -{ -	struct mmc_host *host = NULL; -	struct mmc *mmc_device = NULL; - -	host = malloc(sizeof(struct mmc_host)); -	if (!host) -		return NULL; - -	mmc_device = malloc(sizeof(struct mmc)); -	if (!mmc_device) -		goto err; - -	mmc_device->priv = host; -	return mmc_device; - -err: -	free(host); -	return NULL; -} -  /*   * mmc_host_init - initialize the mmc controller.   * Set initial clock and power for mmc slot.   * Initialize mmc struct and register with mmc framework.   */ -static int arm_pl180_mmci_host_init(struct mmc *dev) +int arm_pl180_mmci_init(struct pl180_mmc_host *host)  { -	struct mmc_host *host = dev->priv; +	struct mmc *dev;  	u32 sdi_u32; -	host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; +	dev = malloc(sizeof(struct mmc)); +	if (!dev) +		return -ENOMEM; -	/* Initially set power-on, full voltage & MMCI read */ -	sdi_u32 = INIT_PWR; -	writel(sdi_u32, &host->base->power); +	memset(dev, 0, sizeof(struct mmc)); +	dev->priv = host; -	/* setting clk freq 505KHz */ -	sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN; -	writel(sdi_u32, &host->base->clock); +	writel(host->pwr_init, &host->base->power); +	writel(host->clkdiv_init, &host->base->clock);  	udelay(CLK_CHANGE_DELAY);  	/* Disable mmc interrupts */  	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;  	writel(sdi_u32, &host->base->mask0); - -	sprintf(dev->name, "MMC"); -	dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1)); +	strncpy(dev->name, host->name, sizeof(dev->name));  	dev->send_cmd = host_request;  	dev->set_ios = host_set_ios;  	dev->init = mmc_host_reset;  	dev->getcd = NULL; -	dev->host_caps = 0; -	dev->voltages = VOLTAGE_WINDOW_MMC; -	dev->f_min = dev->clock; -	dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; - -	return 0; -} - -int arm_pl180_mmci_init(void) -{ -	int error; -	struct mmc *dev; - -	dev = alloc_mmc_struct(); -	if (!dev) -		return -1; - -	error = arm_pl180_mmci_host_init(dev); -	if (error) { -		printf("mmci_host_init error - %d\n", error); -		return -1; -	} - -	dev->b_max = 0; - +	dev->host_caps = host->caps; +	dev->voltages = host->voltages; +	dev->f_min = host->clock_min; +	dev->f_max = host->clock_max; +	dev->b_max = host->b_max;  	mmc_register(dev);  	debug("registered mmc interface number is:%d\n", dev->block_dev.dev); diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 42fbe3e38..06709ed7f 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -26,8 +26,6 @@  #ifndef __ARM_PL180_MMCI_H__  #define __ARM_PL180_MMCI_H__ -int arm_pl180_mmci_init(void); -  #define COMMAND_REG_DELAY	300  #define DATA_REG_DELAY		1000  #define CLK_CHANGE_DELAY	2000 @@ -59,8 +57,13 @@ int arm_pl180_mmci_init(void);  #define SDI_CLKCR_WIDBUS_MASK	0x00001800  #define SDI_CLKCR_WIDBUS_1	0x00000000  #define SDI_CLKCR_WIDBUS_4	0x00000800 +/* V2 only */ +#define SDI_CLKCR_WIDBUS_8	0x00001000 +#define SDI_CLKCR_NEDGE		0x00002000 +#define SDI_CLKCR_HWFC_EN	0x00004000 -#define SDI_CLKCR_CLKDIV_INIT	0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V1 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V2 0x000000FD  /* SDI command register bits */  #define SDI_CMD_CMDINDEX_MASK	0x000000FF @@ -144,6 +147,8 @@ int arm_pl180_mmci_init(void);  #define SDI_DCTRL_DBOOTMODEEN	0x00002000  #define SDI_DCTRL_BUSYMODE	0x00004000  #define SDI_DCTRL_DDR_MODE	0x00008000 +#define SDI_DCTRL_DBLOCKSIZE_V2_MASK   0x7fff0000 +#define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT  16  #define SDI_FIFO_BURST_SIZE	8 @@ -180,4 +185,20 @@ struct sdi_registers {  	u32 pcell_id3;		/* 0xFFC*/  }; +struct pl180_mmc_host { +	struct sdi_registers *base; +	char name[32]; +	unsigned int b_max; +	unsigned int voltages; +	unsigned int caps; +	unsigned int clock_in; +	unsigned int clock_min; +	unsigned int clock_max; +	unsigned int clkdiv_init; +	unsigned int pwr_init; +	int version2; +}; + +int arm_pl180_mmci_init(struct pl180_mmc_host *); +  #endif diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index b6c969d2c..3f8d30db4 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -479,9 +479,10 @@ static int esdhc_init(struct mmc *mmc)  	while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout)  		udelay(1000); +#ifndef ARCH_MXC  	/* Enable cache snooping */ -	if (cfg && !cfg->no_snoop) -		esdhc_write32(®s->scr, 0x00000040); +	esdhc_write32(®s->scr, 0x00000040); +#endif  	esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index c1c286298..fa673cf2c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -151,7 +151,6 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  	printf("CMD_SEND:%d\n", cmd->cmdidx);  	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); -	printf("\t\tFLAG\t\t\t %d\n", cmd->flags);  	ret = mmc->send_cmd(mmc, cmd, data);  	switch (cmd->resp_type) {  		case MMC_RSP_NONE: @@ -213,7 +212,6 @@ int mmc_send_status(struct mmc *mmc, int timeout)  	cmd.resp_type = MMC_RSP_R1;  	if (!mmc_host_is_spi(mmc))  		cmd.cmdarg = mmc->rca << 16; -	cmd.flags = 0;  	do {  		err = mmc_send_cmd(mmc, &cmd, NULL); @@ -253,7 +251,6 @@ int mmc_set_blocklen(struct mmc *mmc, int len)  	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;  	cmd.resp_type = MMC_RSP_R1;  	cmd.cmdarg = len; -	cmd.flags = 0;  	return mmc_send_cmd(mmc, &cmd, NULL);  } @@ -299,7 +296,6 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)  	cmd.cmdidx = start_cmd;  	cmd.cmdarg = start;  	cmd.resp_type = MMC_RSP_R1; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL);  	if (err) @@ -386,7 +382,6 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  		cmd.cmdarg = start * mmc->write_bl_len;  	cmd.resp_type = MMC_RSP_R1; -	cmd.flags = 0;  	data.src = src;  	data.blocks = blkcnt; @@ -405,7 +400,6 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)  		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;  		cmd.cmdarg = 0;  		cmd.resp_type = MMC_RSP_R1b; -		cmd.flags = 0;  		if (mmc_send_cmd(mmc, &cmd, NULL)) {  			printf("mmc fail to send stop cmd\n");  			return 0; @@ -459,7 +453,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)  		cmd.cmdarg = start * mmc->read_bl_len;  	cmd.resp_type = MMC_RSP_R1; -	cmd.flags = 0;  	data.dest = dst;  	data.blocks = blkcnt; @@ -473,7 +466,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)  		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;  		cmd.cmdarg = 0;  		cmd.resp_type = MMC_RSP_R1b; -		cmd.flags = 0;  		if (mmc_send_cmd(mmc, &cmd, NULL)) {  			printf("mmc fail to send stop cmd\n");  			return 0; @@ -525,7 +517,6 @@ int mmc_go_idle(struct mmc* mmc)  	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;  	cmd.cmdarg = 0;  	cmd.resp_type = MMC_RSP_NONE; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL); @@ -548,7 +539,6 @@ sd_send_op_cond(struct mmc *mmc)  		cmd.cmdidx = MMC_CMD_APP_CMD;  		cmd.resp_type = MMC_RSP_R1;  		cmd.cmdarg = 0; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL); @@ -589,7 +579,6 @@ sd_send_op_cond(struct mmc *mmc)  		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;  		cmd.resp_type = MMC_RSP_R3;  		cmd.cmdarg = 0; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL); @@ -618,7 +607,6 @@ int mmc_send_op_cond(struct mmc *mmc)   	cmd.cmdidx = MMC_CMD_SEND_OP_COND;   	cmd.resp_type = MMC_RSP_R3;   	cmd.cmdarg = 0; - 	cmd.flags = 0;   	err = mmc_send_cmd(mmc, &cmd, NULL); @@ -638,8 +626,6 @@ int mmc_send_op_cond(struct mmc *mmc)  		if (mmc->host_caps & MMC_MODE_HC)  			cmd.cmdarg |= OCR_HCS; -		cmd.flags = 0; -  		err = mmc_send_cmd(mmc, &cmd, NULL);  		if (err) @@ -655,7 +641,6 @@ int mmc_send_op_cond(struct mmc *mmc)  		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;  		cmd.resp_type = MMC_RSP_R3;  		cmd.cmdarg = 0; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL); @@ -683,7 +668,6 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)  	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;  	cmd.resp_type = MMC_RSP_R1;  	cmd.cmdarg = 0; -	cmd.flags = 0;  	data.dest = ext_csd;  	data.blocks = 1; @@ -707,7 +691,6 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)  	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |  				 (index << 16) |  				 (value << 8); -	cmd.flags = 0;  	ret = mmc_send_cmd(mmc, &cmd, NULL); @@ -800,7 +783,6 @@ int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)  	cmd.cmdarg = (mode << 31) | 0xffffff;  	cmd.cmdarg &= ~(0xf << (group * 4));  	cmd.cmdarg |= value << (group * 4); -	cmd.flags = 0;  	data.dest = (char *)resp;  	data.blocksize = 64; @@ -829,7 +811,6 @@ int sd_change_freq(struct mmc *mmc)  	cmd.cmdidx = MMC_CMD_APP_CMD;  	cmd.resp_type = MMC_RSP_R1;  	cmd.cmdarg = mmc->rca << 16; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL); @@ -839,7 +820,6 @@ int sd_change_freq(struct mmc *mmc)  	cmd.cmdidx = SD_CMD_APP_SEND_SCR;  	cmd.resp_type = MMC_RSP_R1;  	cmd.cmdarg = 0; -	cmd.flags = 0;  	timeout = 3; @@ -992,7 +972,6 @@ int mmc_startup(struct mmc *mmc)  		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;  		cmd.resp_type = MMC_RSP_R1;  		cmd.cmdarg = 1; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL);  		if (err) @@ -1005,7 +984,6 @@ int mmc_startup(struct mmc *mmc)  		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */  	cmd.resp_type = MMC_RSP_R2;  	cmd.cmdarg = 0; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1023,7 +1001,6 @@ int mmc_startup(struct mmc *mmc)  		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;  		cmd.cmdarg = mmc->rca << 16;  		cmd.resp_type = MMC_RSP_R6; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1038,7 +1015,6 @@ int mmc_startup(struct mmc *mmc)  	cmd.cmdidx = MMC_CMD_SEND_CSD;  	cmd.resp_type = MMC_RSP_R2;  	cmd.cmdarg = mmc->rca << 16; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1115,7 +1091,6 @@ int mmc_startup(struct mmc *mmc)  		cmd.cmdidx = MMC_CMD_SELECT_CARD;  		cmd.resp_type = MMC_RSP_R1;  		cmd.cmdarg = mmc->rca << 16; -		cmd.flags = 0;  		err = mmc_send_cmd(mmc, &cmd, NULL);  		if (err) @@ -1182,7 +1157,6 @@ int mmc_startup(struct mmc *mmc)  			cmd.cmdidx = MMC_CMD_APP_CMD;  			cmd.resp_type = MMC_RSP_R1;  			cmd.cmdarg = mmc->rca << 16; -			cmd.flags = 0;  			err = mmc_send_cmd(mmc, &cmd, NULL);  			if (err) @@ -1191,7 +1165,6 @@ int mmc_startup(struct mmc *mmc)  			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;  			cmd.resp_type = MMC_RSP_R1;  			cmd.cmdarg = 2; -			cmd.flags = 0;  			err = mmc_send_cmd(mmc, &cmd, NULL);  			if (err)  				return err; @@ -1273,7 +1246,6 @@ int mmc_send_if_cond(struct mmc *mmc)  	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */  	cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;  	cmd.resp_type = MMC_RSP_R7; -	cmd.flags = 0;  	err = mmc_send_cmd(mmc, &cmd, NULL); diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index 4187a9412..9a98c6b85 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -43,16 +43,9 @@  #include <asm/arch/sys_proto.h>  #include <asm/arch/dma.h> -/* - * CONFIG_MXS_MMC_DMA: This feature is highly experimental and has no - *                     performance benefit unless you operate the platform with - *                     data cache enabled. This is disabled by default, enable - *                     only if you know what you're doing. - */ -  struct mxsmmc_priv {  	int			id; -	struct mx28_ssp_regs	*regs; +	struct mxs_ssp_regs	*regs;  	uint32_t		clkseq_bypass;  	uint32_t		*clkctrl_ssp;  	uint32_t		buswidth; @@ -61,6 +54,87 @@ struct mxsmmc_priv {  };  #define	MXSMMC_MAX_TIMEOUT	10000 +#define MXSMMC_SMALL_TRANSFER	512 + +static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data) +{ +	struct mxs_ssp_regs *ssp_regs = priv->regs; +	uint32_t *data_ptr; +	int timeout = MXSMMC_MAX_TIMEOUT; +	uint32_t reg; +	uint32_t data_count = data->blocksize * data->blocks; + +	if (data->flags & MMC_DATA_READ) { +		data_ptr = (uint32_t *)data->dest; +		while (data_count && --timeout) { +			reg = readl(&ssp_regs->hw_ssp_status); +			if (!(reg & SSP_STATUS_FIFO_EMPTY)) { +				*data_ptr++ = readl(&ssp_regs->hw_ssp_data); +				data_count -= 4; +				timeout = MXSMMC_MAX_TIMEOUT; +			} else +				udelay(1000); +		} +	} else { +		data_ptr = (uint32_t *)data->src; +		timeout *= 100; +		while (data_count && --timeout) { +			reg = readl(&ssp_regs->hw_ssp_status); +			if (!(reg & SSP_STATUS_FIFO_FULL)) { +				writel(*data_ptr++, &ssp_regs->hw_ssp_data); +				data_count -= 4; +				timeout = MXSMMC_MAX_TIMEOUT; +			} else +				udelay(1000); +		} +	} + +	return timeout ? 0 : COMM_ERR; +} + +static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) +{ +	uint32_t data_count = data->blocksize * data->blocks; +	uint32_t cache_data_count; +	int dmach; +	struct mxs_dma_desc *desc = priv->desc; + +	memset(desc, 0, sizeof(struct mxs_dma_desc)); +	desc->address = (dma_addr_t)desc; + +	if (data_count % ARCH_DMA_MINALIGN) +		cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); +	else +		cache_data_count = data_count; + +	if (data->flags & MMC_DATA_READ) { +		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; +		priv->desc->cmd.address = (dma_addr_t)data->dest; +	} else { +		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; +		priv->desc->cmd.address = (dma_addr_t)data->src; + +		/* Flush data to DRAM so DMA can pick them up */ +		flush_dcache_range((uint32_t)priv->desc->cmd.address, +			(uint32_t)(priv->desc->cmd.address + cache_data_count)); +	} + +	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | +				(data_count << MXS_DMA_DESC_BYTES_OFFSET); + +	dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; +	mxs_dma_desc_append(dmach, priv->desc); +	if (mxs_dma_go(dmach)) +		return COMM_ERR; + +	/* The data arrived into DRAM, invalidate cache over them */ +	if (data->flags & MMC_DATA_READ) { +		invalidate_dcache_range((uint32_t)priv->desc->cmd.address, +			(uint32_t)(priv->desc->cmd.address + cache_data_count)); +	} + +	return 0; +}  /*   * Sends a command out on the bus.  Takes the mmc pointer, @@ -70,16 +144,11 @@ static int  mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  {  	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; -	struct mx28_ssp_regs *ssp_regs = priv->regs; +	struct mxs_ssp_regs *ssp_regs = priv->regs;  	uint32_t reg;  	int timeout; -	uint32_t data_count;  	uint32_t ctrl0; -#ifndef CONFIG_MXS_MMC_DMA -	uint32_t *data_ptr; -#else -	uint32_t cache_data_count; -#endif +	int ret;  	debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx); @@ -117,6 +186,11 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  	if (cmd->resp_type & MMC_RSP_136)	/* It's a 136 bits response */  		ctrl0 |= SSP_CTRL0_LONG_RESP; +	if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER)) +		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr); +	else +		writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set); +  	/* Command index */  	reg = readl(&ssp_regs->hw_ssp_cmd0);  	reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC); @@ -197,75 +271,23 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  	if (!data)  		return 0; -	data_count = data->blocksize * data->blocks; -	timeout = MXSMMC_MAX_TIMEOUT; - -#ifdef CONFIG_MXS_MMC_DMA -	if (data_count % ARCH_DMA_MINALIGN) -		cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); -	else -		cache_data_count = data_count; - -	if (data->flags & MMC_DATA_READ) { -		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; -		priv->desc->cmd.address = (dma_addr_t)data->dest; -	} else { -		priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; -		priv->desc->cmd.address = (dma_addr_t)data->src; - -		/* Flush data to DRAM so DMA can pick them up */ -		flush_dcache_range((uint32_t)priv->desc->cmd.address, -			(uint32_t)(priv->desc->cmd.address + cache_data_count)); -	} - -	priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | -				(data_count << MXS_DMA_DESC_BYTES_OFFSET); - - -	mxs_dma_desc_append(MXS_DMA_CHANNEL_AHB_APBH_SSP0, priv->desc); -	if (mxs_dma_go(MXS_DMA_CHANNEL_AHB_APBH_SSP0)) { -		printf("MMC%d: DMA transfer failed\n", mmc->block_dev.dev); -		return COMM_ERR; -	} - -	/* The data arrived into DRAM, invalidate cache over them */ -	if (data->flags & MMC_DATA_READ) { -		invalidate_dcache_range((uint32_t)priv->desc->cmd.address, -			(uint32_t)(priv->desc->cmd.address + cache_data_count)); -	} -#else -	if (data->flags & MMC_DATA_READ) { -		data_ptr = (uint32_t *)data->dest; -		while (data_count && --timeout) { -			reg = readl(&ssp_regs->hw_ssp_status); -			if (!(reg & SSP_STATUS_FIFO_EMPTY)) { -				*data_ptr++ = readl(&ssp_regs->hw_ssp_data); -				data_count -= 4; -				timeout = MXSMMC_MAX_TIMEOUT; -			} else -				udelay(1000); +	if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) { +		ret = mxsmmc_send_cmd_pio(priv, data); +		if (ret) { +			printf("MMC%d: Data timeout with command %d " +				"(status 0x%08x)!\n", +				mmc->block_dev.dev, cmd->cmdidx, reg); +			return ret;  		}  	} else { -		data_ptr = (uint32_t *)data->src; -		timeout *= 100; -		while (data_count && --timeout) { -			reg = readl(&ssp_regs->hw_ssp_status); -			if (!(reg & SSP_STATUS_FIFO_FULL)) { -				writel(*data_ptr++, &ssp_regs->hw_ssp_data); -				data_count -= 4; -				timeout = MXSMMC_MAX_TIMEOUT; -			} else -				udelay(1000); +		ret = mxsmmc_send_cmd_dma(priv, data); +		if (ret) { +			printf("MMC%d: DMA transfer failed\n", +				mmc->block_dev.dev); +			return ret;  		}  	} -	if (!timeout) { -		printf("MMC%d: Data timeout with command %d (status 0x%08x)!\n", -			mmc->block_dev.dev, cmd->cmdidx, reg); -		return COMM_ERR; -	} -#endif -  	/* Check data errors */  	reg = readl(&ssp_regs->hw_ssp_status);  	if (reg & @@ -282,7 +304,7 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)  static void mxsmmc_set_ios(struct mmc *mmc)  {  	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; -	struct mx28_ssp_regs *ssp_regs = priv->regs; +	struct mxs_ssp_regs *ssp_regs = priv->regs;  	/* Set the clock speed */  	if (mmc->clock) @@ -311,16 +333,16 @@ static void mxsmmc_set_ios(struct mmc *mmc)  static int mxsmmc_init(struct mmc *mmc)  {  	struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; -	struct mx28_ssp_regs *ssp_regs = priv->regs; +	struct mxs_ssp_regs *ssp_regs = priv->regs;  	/* Reset SSP */ -	mx28_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); +	mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg);  	/* 8 bits word length in MMC mode */  	clrsetbits_le32(&ssp_regs->hw_ssp_ctrl1, -		SSP_CTRL1_SSP_MODE_MASK | SSP_CTRL1_WORD_LENGTH_MASK, -		SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS | -		SSP_CTRL1_DMA_ENABLE); +		SSP_CTRL1_SSP_MODE_MASK | SSP_CTRL1_WORD_LENGTH_MASK | +		SSP_CTRL1_DMA_ENABLE, +		SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS);  	/* Set initial bit clock 400 KHz */  	mx28_set_ssp_busclock(priv->id, 400); @@ -335,8 +357,8 @@ static int mxsmmc_init(struct mmc *mmc)  int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))  { -	struct mx28_clkctrl_regs *clkctrl_regs = -		(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; +	struct mxs_clkctrl_regs *clkctrl_regs = +		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;  	struct mmc *mmc = NULL;  	struct mxsmmc_priv *priv = NULL;  	int ret; @@ -366,22 +388,22 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))  	priv->id = id;  	switch (id) {  	case 0: -		priv->regs = (struct mx28_ssp_regs *)MXS_SSP0_BASE; +		priv->regs = (struct mxs_ssp_regs *)MXS_SSP0_BASE;  		priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP0;  		priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp0;  		break;  	case 1: -		priv->regs = (struct mx28_ssp_regs *)MXS_SSP1_BASE; +		priv->regs = (struct mxs_ssp_regs *)MXS_SSP1_BASE;  		priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP1;  		priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp1;  		break;  	case 2: -		priv->regs = (struct mx28_ssp_regs *)MXS_SSP2_BASE; +		priv->regs = (struct mxs_ssp_regs *)MXS_SSP2_BASE;  		priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP2;  		priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp2;  		break;  	case 3: -		priv->regs = (struct mx28_ssp_regs *)MXS_SSP3_BASE; +		priv->regs = (struct mxs_ssp_regs *)MXS_SSP3_BASE;  		priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP3;  		priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp3;  		break; diff --git a/drivers/mmc/spl_mmc_load.c b/drivers/mmc/spl_mmc_load.c new file mode 100644 index 000000000..79a68fbcf --- /dev/null +++ b/drivers/mmc/spl_mmc_load.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <mmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void mmc_load_image(struct mmc *mmc) +{ +	s32 err; +	void (*uboot)(void) __noreturn; + +	err = mmc->block_dev.block_read(0, CONFIG_SYS_MMC_U_BOOT_OFFS, +			CONFIG_SYS_MMC_U_BOOT_SIZE/512, +			(u32 *)CONFIG_SYS_TEXT_BASE); + +	if (err <= 0) { +		printf("spl: error reading image %s, err - %d\n", +			"u-boot.img", err); +		hang(); +	} +	uboot = (void *) CONFIG_SYS_TEXT_BASE; +	(*uboot)(); +} + +void spl_mmc_load(void) +{ +	struct mmc *mmc; +	int err; +	void (mmc_load_image)(struct mmc *mmc) __noreturn; + +	mmc_initialize(gd->bd); +	mmc = find_mmc_device(0); +	if (!mmc) { +		puts("spl: mmc device not found!!\n"); +		hang(); +	} else { +		puts("spl: mmc device found\n"); +	} +	err = mmc_init(mmc); +	if (err) { +		printf("spl: mmc init failed: err - %d\n", err); +		hang(); +	} +	mmc_load_image(mmc); +} diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 29bf58359..ddfa7279c 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -39,31 +39,31 @@ struct mmc_host mmc_host[4];   * @param host		Structure to fill in (base, reg, mmc_id)   * @param dev_index	Device index (0-3)   */ -static void tegra2_get_setup(struct mmc_host *host, int dev_index) +static void tegra20_get_setup(struct mmc_host *host, int dev_index)  { -	debug("tegra2_get_base_mmc: dev_index = %d\n", dev_index); +	debug("tegra20_get_base_mmc: dev_index = %d\n", dev_index);  	switch (dev_index) {  	case 1: -		host->base = TEGRA2_SDMMC3_BASE; +		host->base = TEGRA20_SDMMC3_BASE;  		host->mmc_id = PERIPH_ID_SDMMC3;  		break;  	case 2: -		host->base = TEGRA2_SDMMC2_BASE; +		host->base = TEGRA20_SDMMC2_BASE;  		host->mmc_id = PERIPH_ID_SDMMC2;  		break;  	case 3: -		host->base = TEGRA2_SDMMC1_BASE; +		host->base = TEGRA20_SDMMC1_BASE;  		host->mmc_id = PERIPH_ID_SDMMC1;  		break;  	case 0:  	default: -		host->base = TEGRA2_SDMMC4_BASE; +		host->base = TEGRA20_SDMMC4_BASE;  		host->mmc_id = PERIPH_ID_SDMMC4;  		break;  	} -	host->reg = (struct tegra2_mmc *)host->base; +	host->reg = (struct tegra20_mmc *)host->base;  }  static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) @@ -345,7 +345,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)  	debug(" mmc_change_clock called\n");  	/* -	 * Change Tegra2 SDMMCx clock divisor here. Source is 216MHz, +	 * Change Tegra20 SDMMCx clock divisor here. Source is 216MHz,  	 * PLLP_OUT0  	 */  	if (clock == 0) @@ -494,11 +494,11 @@ static int mmc_core_init(struct mmc *mmc)  	return 0;  } -int tegra2_mmc_getcd(struct mmc *mmc) +int tegra20_mmc_getcd(struct mmc *mmc)  {  	struct mmc_host *host = (struct mmc_host *)mmc->priv; -	debug("tegra2_mmc_getcd called\n"); +	debug("tegra20_mmc_getcd called\n");  	if (host->cd_gpio >= 0)  		return !gpio_get_value(host->cd_gpio); @@ -506,13 +506,13 @@ int tegra2_mmc_getcd(struct mmc *mmc)  	return 1;  } -int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) +int tegra20_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  {  	struct mmc_host *host;  	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */  	struct mmc *mmc; -	debug(" tegra2_mmc_init: index %d, bus width %d " +	debug(" tegra20_mmc_init: index %d, bus width %d "  		"pwr_gpio %d cd_gpio %d\n",  		dev_index, bus_width, pwr_gpio, cd_gpio); @@ -521,7 +521,7 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	host->clock = 0;  	host->pwr_gpio = pwr_gpio;  	host->cd_gpio = cd_gpio; -	tegra2_get_setup(host, dev_index); +	tegra20_get_setup(host, dev_index);  	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); @@ -539,12 +539,12 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	mmc = &mmc_dev[dev_index]; -	sprintf(mmc->name, "Tegra2 SD/MMC"); +	sprintf(mmc->name, "Tegra20 SD/MMC");  	mmc->priv = host;  	mmc->send_cmd = mmc_send_cmd;  	mmc->set_ios = mmc_set_ios;  	mmc->init = mmc_core_init; -	mmc->getcd = tegra2_mmc_getcd; +	mmc->getcd = tegra20_mmc_getcd;  	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;  	if (bus_width == 8) @@ -559,7 +559,7 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)  	 * max freq is highest HS eMMC clock as per the SD/MMC spec  	 *  (actually 52MHz)  	 * Both of these are the closest equivalents w/216MHz source -	 *  clock and Tegra2 SDMMC divisors. +	 *  clock and Tegra20 SDMMC divisors.  	 */  	mmc->f_min = 375000;  	mmc->f_max = 48000000; diff --git a/drivers/mmc/tegra_mmc.h b/drivers/mmc/tegra_mmc.h index f9cdcaaaa..b1f256419 100644 --- a/drivers/mmc/tegra_mmc.h +++ b/drivers/mmc/tegra_mmc.h @@ -22,13 +22,13 @@  #ifndef __TEGRA_MMC_H_  #define __TEGRA_MMC_H_ -#define TEGRA2_SDMMC1_BASE	0xC8000000 -#define TEGRA2_SDMMC2_BASE	0xC8000200 -#define TEGRA2_SDMMC3_BASE	0xC8000400 -#define TEGRA2_SDMMC4_BASE	0xC8000600 +#define TEGRA20_SDMMC1_BASE	0xC8000000 +#define TEGRA20_SDMMC2_BASE	0xC8000200 +#define TEGRA20_SDMMC3_BASE	0xC8000400 +#define TEGRA20_SDMMC4_BASE	0xC8000600  #ifndef __ASSEMBLY__ -struct tegra2_mmc { +struct tegra20_mmc {  	unsigned int	sysad;		/* _SYSTEM_ADDRESS_0 */  	unsigned short	blksize;	/* _BLOCK_SIZE_BLOCK_COUNT_0 15:00 */  	unsigned short	blkcnt;		/* _BLOCK_SIZE_BLOCK_COUNT_0 31:16 */ @@ -118,7 +118,7 @@ struct tegra2_mmc {  #define TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE			(1 << 1)  struct mmc_host { -	struct tegra2_mmc *reg; +	struct tegra20_mmc *reg;  	unsigned int version;	/* SDHCI spec. version */  	unsigned int clock;	/* Current clock (MHz) */  	unsigned int base;	/* Base address, SDMMC1/2/3/4 */ |