diff options
| -rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 441 | ||||
| -rw-r--r-- | drivers/mmc/arm_pl180_mmci.h | 183 | 
3 files changed, 625 insertions, 0 deletions
| diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 9aca3a2bd..a8fe17a6f 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -32,6 +32,7 @@ COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o  COBJS-$(CONFIG_GENERIC_MMC) += mmc.o  COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o  COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o +COBJS-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o  COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o  COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o  COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c new file mode 100644 index 000000000..245f48294 --- /dev/null +++ b/drivers/mmc/arm_pl180_mmci.c @@ -0,0 +1,441 @@ +/* + * ARM PrimeCell MultiMedia Card Interface - PL180 + * + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ulf Hansson <ulf.hansson@stericsson.com> + * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com> + * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org> + * + * 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 + */ + +/* #define DEBUG */ + +#include <asm/io.h> +#include "common.h" +#include <errno.h> +#include <mmc.h> +#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; + +	statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL; +	if ((cmd->resp_type & MMC_RSP_PRESENT)) +		statusmask |= SDI_STA_CMDREND; +	else +		statusmask |= SDI_STA_CMDSENT; + +	do +		hoststatus = readl(&host->base->status) & statusmask; +	while (!hoststatus); + +	writel(statusmask, &host->base->status_clear); +	if (hoststatus & SDI_STA_CTIMEOUT) { +		printf("CMD%d time out\n", cmd->cmdidx); +		return -ETIMEDOUT; +	} else if ((hoststatus & SDI_STA_CCRCFAIL) && +		   (cmd->flags & MMC_RSP_CRC)) { +		printf("CMD%d CRC error\n", cmd->cmdidx); +		return -EILSEQ; +	} + +	if (cmd->resp_type & MMC_RSP_PRESENT) { +		cmd->response[0] = readl(&host->base->response0); +		cmd->response[1] = readl(&host->base->response1); +		cmd->response[2] = readl(&host->base->response2); +		cmd->response[3] = readl(&host->base->response3); +		debug("CMD%d response[0]:0x%08X, response[1]:0x%08X, " +			"response[2]:0x%08X, response[3]:0x%08X\n", +			cmd->cmdidx, cmd->response[0], cmd->response[1], +			cmd->response[2], cmd->response[3]); +	} + +	return 0; +} + +/* send command to the mmc card and wait for results */ +static int do_command(struct mmc *dev, struct mmc_cmd *cmd) +{ +	int result; +	u32 sdi_cmd = 0; +	struct mmc_host *host = dev->priv; + +	sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN); + +	if (cmd->resp_type) { +		sdi_cmd |= SDI_CMD_WAITRESP; +		if (cmd->resp_type & MMC_RSP_136) +			sdi_cmd |= SDI_CMD_LONGRESP; +	} + +	writel((u32)cmd->cmdarg, &host->base->argument); +	udelay(COMMAND_REG_DELAY); +	writel(sdi_cmd, &host->base->command); +	result = wait_for_command_end(dev, cmd); + +	/* After CMD2 set RCA to a none zero value. */ +	if ((result == 0) && (cmd->cmdidx == MMC_CMD_ALL_SEND_CID)) +		dev->rca = 10; + +	/* After CMD3 open drain is switched off and push pull is used. */ +	if ((result == 0) && (cmd->cmdidx == MMC_CMD_SET_RELATIVE_ADDR)) { +		u32 sdi_pwr = readl(&host->base->power) & ~SDI_PWR_OPD; +		writel(sdi_pwr, &host->base->power); +	} + +	return result; +} + +static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize) +{ +	u32 *tempbuff = dest; +	int i; +	u64 xfercount = blkcount * blksize; +	struct mmc_host *host = dev->priv; +	u32 status, status_err; + +	debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); + +	status = readl(&host->base->status); +	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | +			       SDI_STA_RXOVERR); +	while (!status_err && +	       (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32))) { +		if (status & SDI_STA_RXFIFOBR) { +			for (i = 0; i < SDI_FIFO_BURST_SIZE; i++) +				*(tempbuff + i) = readl(&host->base->fifo); +			tempbuff += SDI_FIFO_BURST_SIZE; +			xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32); +		} +		status = readl(&host->base->status); +		status_err = status & +			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_RXOVERR); +	} + +	if (status & SDI_STA_DTIMEOUT) { +		printf("Read data timed out, xfercount: %llu, status: 0x%08X\n", +			xfercount, status); +		return -ETIMEDOUT; +	} else if (status & SDI_STA_DCRCFAIL) { +		printf("Read data blk CRC error: 0x%x\n", status); +		return -EILSEQ; +	} else if (status & SDI_STA_RXOVERR) { +		printf("Read data RX overflow error\n"); +		return -EIO; +	} + +	while ((!status_err) && (xfercount >= sizeof(u32))) { +		if (status & SDI_STA_RXDAVL) { +			*(tempbuff) = readl(&host->base->fifo); +			tempbuff++; +			xfercount -= sizeof(u32); +		} +		status = readl(&host->base->status); +		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | +				       SDI_STA_RXOVERR); +	} + +	status_err = status & +		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND | +		 SDI_STA_RXOVERR); +	while (!status_err) { +		status = readl(&host->base->status); +		status_err = status & +			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND | +			 SDI_STA_RXOVERR); +	} + +	if (status & SDI_STA_DTIMEOUT) { +		printf("Read data timed out, xfercount: %llu, status: 0x%08X\n", +			xfercount, status); +		return -ETIMEDOUT; +	} else if (status & SDI_STA_DCRCFAIL) { +		printf("Read data bytes CRC error: 0x%x\n", status); +		return -EILSEQ; +	} else if (status & SDI_STA_RXOVERR) { +		printf("Read data RX overflow error\n"); +		return -EIO; +	} + +	writel(SDI_ICR_MASK, &host->base->status_clear); + +	if (xfercount) { +		printf("Read data error, xfercount: %llu\n", xfercount); +		return -ENOBUFS; +	} + +	return 0; +} + +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; +	u32 status, status_err; + +	debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); + +	status = readl(&host->base->status); +	status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT); +	while (!status_err && xfercount) { +		if (status & SDI_STA_TXFIFOBW) { +			if (xfercount >= SDI_FIFO_BURST_SIZE * sizeof(u32)) { +				for (i = 0; i < SDI_FIFO_BURST_SIZE; i++) +					writel(*(tempbuff + i), +						&host->base->fifo); +				tempbuff += SDI_FIFO_BURST_SIZE; +				xfercount -= SDI_FIFO_BURST_SIZE * sizeof(u32); +			} else { +				while (xfercount >= sizeof(u32)) { +					writel(*(tempbuff), &host->base->fifo); +					tempbuff++; +					xfercount -= sizeof(u32); +				} +			} +		} +		status = readl(&host->base->status); +		status_err = status & (SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT); +	} + +	status_err = status & +		(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND); +	while (!status_err) { +		status = readl(&host->base->status); +		status_err = status & +			(SDI_STA_DCRCFAIL | SDI_STA_DTIMEOUT | SDI_STA_DBCKEND); +	} + +	if (status & SDI_STA_DTIMEOUT) { +		printf("Write data timed out, xfercount:%llu,status:0x%08X\n", +		       xfercount, status); +		return -ETIMEDOUT; +	} else if (status & SDI_STA_DCRCFAIL) { +		printf("Write data CRC error\n"); +		return -EILSEQ; +	} + +	writel(SDI_ICR_MASK, &host->base->status_clear); + +	if (xfercount) { +		printf("Write data error, xfercount:%llu", xfercount); +		return -ENOBUFS; +	} + +	return 0; +} + +static int do_data_transfer(struct mmc *dev, +			    struct mmc_cmd *cmd, +			    struct mmc_data *data) +{ +	int error = -ETIMEDOUT; +	struct 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; + +	writel(SDI_DTIMER_DEFAULT, &host->base->datatimer); +	writel(data_len, &host->base->datalength); +	udelay(DATA_REG_DELAY); + +	if (data->flags & MMC_DATA_READ) { +		data_ctrl |= SDI_DCTRL_DTDIR_IN; +		writel(data_ctrl, &host->base->datactrl); + +		error = do_command(dev, cmd); +		if (error) +			return error; + +		error = read_bytes(dev, (u32 *)data->dest, (u32)data->blocks, +				   (u32)data->blocksize); +	} else if (data->flags & MMC_DATA_WRITE) { +		error = do_command(dev, cmd); +		if (error) +			return error; + +		writel(data_ctrl, &host->base->datactrl); +		error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks, +				    (u32)data->blocksize); +	} + +	return error; +} + +static int host_request(struct mmc *dev, +			struct mmc_cmd *cmd, +			struct mmc_data *data) +{ +	int result; + +	if (data) +		result = do_data_transfer(dev, cmd, data); +	else +		result = do_command(dev, cmd); + +	return result; +} + +/* 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; + +	writel(sdi_u32, &host->base->power); + +	return 0; +} + +static void host_set_ios(struct mmc *dev) +{ +	struct mmc_host *host = dev->priv; +	u32 sdi_clkcr; + +	sdi_clkcr = readl(&host->base->clock); + +	/* Ramp up the clock rate */ +	if (dev->clock) { +		u32 clkdiv = 0; + +		if (dev->clock >= dev->f_max) +			dev->clock = dev->f_max; + +		clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1; + +		if (clkdiv > SDI_CLKCR_CLKDIV_MASK) +			clkdiv = SDI_CLKCR_CLKDIV_MASK; + +		sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK); +		sdi_clkcr |= clkdiv; +	} + +	/* Set the bus width */ +	if (dev->bus_width) { +		u32 buswidth = 0; + +		switch (dev->bus_width) { +		case 1: +			buswidth |= SDI_CLKCR_WIDBUS_1; +			break; +		case 4: +			buswidth |= SDI_CLKCR_WIDBUS_4; +			break; +		default: +			printf("Invalid bus width\n"); +			break; +		} +		sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); +		sdi_clkcr |= buswidth; +	} + +	writel(sdi_clkcr, &host->base->clock); +	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) +{ +	struct mmc_host *host = dev->priv; +	u32 sdi_u32; + +	host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + +	/* Initially set power-on, full voltage & MMCI read */ +	sdi_u32 = INIT_PWR; +	writel(sdi_u32, &host->base->power); + +	/* setting clk freq 505KHz */ +	sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN; +	writel(sdi_u32, &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)); +	dev->send_cmd = host_request; +	dev->set_ios = host_set_ios; +	dev->init = mmc_host_reset; +	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; +	} + +	mmc_register(dev); +	debug("registered mmc interface number is:%d\n", dev->block_dev.dev); + +	return 0; +} diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h new file mode 100644 index 000000000..42fbe3e38 --- /dev/null +++ b/drivers/mmc/arm_pl180_mmci.h @@ -0,0 +1,183 @@ +/* + * ARM PrimeCell MultiMedia Card Interface - PL180 + * + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Ulf Hansson <ulf.hansson@stericsson.com> + * Author: Martin Lundholm <martin.xa.lundholm@stericsson.com> + * Ported to drivers/mmc/ by: Matt Waddel <matt.waddel@linaro.org> + * + * 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 + */ + +#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 + +#define INIT_PWR		0xBF /* Power on, full power, not open drain */ +#define ARM_MCLK		(100*1000*1000) + +/* SDI Power Control register bits */ +#define SDI_PWR_PWRCTRL_MASK	0x00000003 +#define SDI_PWR_PWRCTRL_ON	0x00000003 +#define SDI_PWR_PWRCTRL_OFF	0x00000000 +#define SDI_PWR_DAT2DIREN	0x00000004 +#define SDI_PWR_CMDDIREN	0x00000008 +#define SDI_PWR_DAT0DIREN	0x00000010 +#define SDI_PWR_DAT31DIREN	0x00000020 +#define SDI_PWR_OPD		0x00000040 +#define SDI_PWR_FBCLKEN		0x00000080 +#define SDI_PWR_DAT74DIREN	0x00000100 +#define SDI_PWR_RSTEN		0x00000200 + +#define VOLTAGE_WINDOW_MMC	0x00FF8080 +#define VOLTAGE_WINDOW_SD	0x80010000 + +/* SDI clock control register bits */ +#define SDI_CLKCR_CLKDIV_MASK	0x000000FF +#define SDI_CLKCR_CLKEN		0x00000100 +#define SDI_CLKCR_PWRSAV	0x00000200 +#define SDI_CLKCR_BYPASS	0x00000400 +#define SDI_CLKCR_WIDBUS_MASK	0x00001800 +#define SDI_CLKCR_WIDBUS_1	0x00000000 +#define SDI_CLKCR_WIDBUS_4	0x00000800 + +#define SDI_CLKCR_CLKDIV_INIT	0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ + +/* SDI command register bits */ +#define SDI_CMD_CMDINDEX_MASK	0x000000FF +#define SDI_CMD_WAITRESP	0x00000040 +#define SDI_CMD_LONGRESP	0x00000080 +#define SDI_CMD_WAITINT		0x00000100 +#define SDI_CMD_WAITPEND	0x00000200 +#define SDI_CMD_CPSMEN		0x00000400 +#define SDI_CMD_SDIOSUSPEND	0x00000800 +#define SDI_CMD_ENDCMDCOMPL	0x00001000 +#define SDI_CMD_NIEN		0x00002000 +#define SDI_CMD_CE_ATACMD	0x00004000 +#define SDI_CMD_CBOOTMODEEN	0x00008000 + +#define SDI_DTIMER_DEFAULT	0xFFFF0000 + +/* SDI Status register bits */ +#define SDI_STA_CCRCFAIL	0x00000001 +#define SDI_STA_DCRCFAIL	0x00000002 +#define SDI_STA_CTIMEOUT	0x00000004 +#define SDI_STA_DTIMEOUT	0x00000008 +#define SDI_STA_TXUNDERR	0x00000010 +#define SDI_STA_RXOVERR		0x00000020 +#define SDI_STA_CMDREND		0x00000040 +#define SDI_STA_CMDSENT		0x00000080 +#define SDI_STA_DATAEND		0x00000100 +#define SDI_STA_STBITERR	0x00000200 +#define SDI_STA_DBCKEND		0x00000400 +#define SDI_STA_CMDACT		0x00000800 +#define SDI_STA_TXACT		0x00001000 +#define SDI_STA_RXACT		0x00002000 +#define SDI_STA_TXFIFOBW	0x00004000 +#define SDI_STA_RXFIFOBR	0x00008000 +#define SDI_STA_TXFIFOF		0x00010000 +#define SDI_STA_RXFIFOF		0x00020000 +#define SDI_STA_TXFIFOE		0x00040000 +#define SDI_STA_RXFIFOE		0x00080000 +#define SDI_STA_TXDAVL		0x00100000 +#define SDI_STA_RXDAVL		0x00200000 +#define SDI_STA_SDIOIT		0x00400000 +#define SDI_STA_CEATAEND	0x00800000 +#define SDI_STA_CARDBUSY	0x01000000 +#define SDI_STA_BOOTMODE	0x02000000 +#define SDI_STA_BOOTACKERR	0x04000000 +#define SDI_STA_BOOTACKTIMEOUT	0x08000000 +#define SDI_STA_RSTNEND		0x10000000 + +/* SDI Interrupt Clear register bits */ +#define SDI_ICR_MASK		0x1DC007FF +#define SDI_ICR_CCRCFAILC	0x00000001 +#define SDI_ICR_DCRCFAILC	0x00000002 +#define SDI_ICR_CTIMEOUTC	0x00000004 +#define SDI_ICR_DTIMEOUTC	0x00000008 +#define SDI_ICR_TXUNDERRC	0x00000010 +#define SDI_ICR_RXOVERRC	0x00000020 +#define SDI_ICR_CMDRENDC	0x00000040 +#define SDI_ICR_CMDSENTC	0x00000080 +#define SDI_ICR_DATAENDC	0x00000100 +#define SDI_ICR_STBITERRC	0x00000200 +#define SDI_ICR_DBCKENDC	0x00000400 +#define SDI_ICR_SDIOITC		0x00400000 +#define SDI_ICR_CEATAENDC	0x00800000 +#define SDI_ICR_BUSYENDC	0x01000000 +#define SDI_ICR_BOOTACKERRC	0x04000000 +#define SDI_ICR_BOOTACKTIMEOUTC	0x08000000 +#define SDI_ICR_RSTNENDC	0x10000000 + +#define SDI_MASK0_MASK		0x1FFFFFFF + +/* SDI Data control register bits */ +#define SDI_DCTRL_DTEN		0x00000001 +#define SDI_DCTRL_DTDIR_IN	0x00000002 +#define SDI_DCTRL_DTMODE_STREAM	0x00000004 +#define SDI_DCTRL_DMAEN		0x00000008 +#define SDI_DCTRL_DBLKSIZE_MASK	0x000000F0 +#define SDI_DCTRL_RWSTART	0x00000100 +#define SDI_DCTRL_RWSTOP	0x00000200 +#define SDI_DCTRL_RWMOD		0x00000200 +#define SDI_DCTRL_SDIOEN	0x00000800 +#define SDI_DCTRL_DMAREQCTL	0x00001000 +#define SDI_DCTRL_DBOOTMODEEN	0x00002000 +#define SDI_DCTRL_BUSYMODE	0x00004000 +#define SDI_DCTRL_DDR_MODE	0x00008000 + +#define SDI_FIFO_BURST_SIZE	8 + +struct sdi_registers { +	u32 power;		/* 0x00*/ +	u32 clock;		/* 0x04*/ +	u32 argument;		/* 0x08*/ +	u32 command;		/* 0x0c*/ +	u32 respcommand;	/* 0x10*/ +	u32 response0;		/* 0x14*/ +	u32 response1;		/* 0x18*/ +	u32 response2;		/* 0x1c*/ +	u32 response3;		/* 0x20*/ +	u32 datatimer;		/* 0x24*/ +	u32 datalength;		/* 0x28*/ +	u32 datactrl;		/* 0x2c*/ +	u32 datacount;		/* 0x30*/ +	u32 status;		/* 0x34*/ +	u32 status_clear;	/* 0x38*/ +	u32 mask0;		/* 0x3c*/ +	u32 mask1;		/* 0x40*/ +	u32 card_select;	/* 0x44*/ +	u32 fifo_count;		/* 0x48*/ +	u32 padding1[(0x80-0x4C)>>2]; +	u32 fifo;		/* 0x80*/ +	u32 padding2[(0xFE0-0x84)>>2]; +	u32 periph_id0;		/* 0xFE0 mmc Peripheral Identifcation Register*/ +	u32 periph_id1;		/* 0xFE4*/ +	u32 periph_id2;		/* 0xFE8*/ +	u32 periph_id3;		/* 0xFEC*/ +	u32 pcell_id0;		/* 0xFF0*/ +	u32 pcell_id1;		/* 0xFF4*/ +	u32 pcell_id2;		/* 0xFF8*/ +	u32 pcell_id3;		/* 0xFFC*/ +}; + +#endif |