All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress
@ 2011-02-25  2:35 matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
                   ` (9 more replies)
  0 siblings, 10 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-02-25  2:35 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
The Versatile Express was the test platform for these changes.

Matt Waddel (3):
  MMC: Max blocks value adjustable
  MMC: Add support for PL180 ARM mmc device
  ARMV7: Vexpress: Add MMC support

 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
 drivers/mmc/Makefile                 |    1 +
 drivers/mmc/mmc.c                    |   19 +-
 drivers/mmc/mmci.c                   |  452 ++++++++++++++++++++++++++++++++++
 drivers/mmc/mmci.h                   |  181 ++++++++++++++
 include/configs/ca9x4_ct_vxp.h       |    4 +
 6 files changed, 656 insertions(+), 10 deletions(-)
 create mode 100644 drivers/mmc/mmci.c
 create mode 100644 drivers/mmc/mmci.h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH 1/3] MMC: Max blocks value adjustable
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
@ 2011-02-25  2:35 ` matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-02-25  2:35 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

The maximum blocks value was hardcoded to 65535 due to a 16 bit
register length.  The value can change for different platforms.
This patch makes the default the current value of 65535, but it
is configurable for other platforms.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/mmc.c |   19 +++++++++----------
 1 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6805b33..d69eaa1 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -33,6 +33,11 @@
 #include <mmc.h>
 #include <div64.h>
 
+/* Set block count limit because of 16 bit register limit on some hardware*/
+#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
+#endif
+
 static struct list_head mmc_devices;
 static int cur_dev_num = -1;
 
@@ -139,11 +144,8 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
 		return 0;
 
 	do {
-		/*
-		 * The 65535 constraint comes from some hardware has
-		 * only 16 bit width block number counter
-		 */
-		cur = (blocks_todo > 65535) ? 65535 : blocks_todo;
+		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
+		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
 			return 0;
 		blocks_todo -= cur;
@@ -215,11 +217,8 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
 		return 0;
 
 	do {
-		/*
-		 * The 65535 constraint comes from some hardware has
-		 * only 16 bit width block number counter
-		 */
-		cur = (blocks_todo > 65535) ? 65535 : blocks_todo;
+		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
+		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
 			return 0;
 		blocks_todo -= cur;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH 2/3] MMC: Add support for PL180 ARM mmc device
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
@ 2011-02-25  2:35 ` matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-02-25  2:35 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Add support for the ARM PrimeCell MultiMedia Interface - PL180.
Ported from original device driver written by ST-Ericsson.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/Makefile |    1 +
 drivers/mmc/mmci.c   |  452 ++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/mmci.h   |  181 ++++++++++++++++++++
 3 files changed, 634 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/mmci.c
 create mode 100644 drivers/mmc/mmci.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 3496f0a..999970b 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+COBJS-$(CONFIG_MMCI) += 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/mmci.c b/drivers/mmc/mmci.c
new file mode 100644
index 0000000..ba2f335
--- /dev/null
+++ b/drivers/mmc/mmci.c
@@ -0,0 +1,452 @@
+/*
+ * 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 "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 convert_from_bytes_to_power_of_two(unsigned int x)
+{
+	int y = 0;
+	y = (x & 0xAAAA) ? 1 : 0;
+	y |= ((x & 0xCCCC) ? 1 : 0) << 1;
+	y |= ((x & 0xF0F0) ? 1 : 0) << 2;
+	y |= ((x & 0xFF00) ? 1 : 0) << 3;
+
+	return y;
+}
+
+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 = convert_from_bytes_to_power_of_two(data->blocksize);
+	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 = ((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 mmc_host_init(struct mmc *dev)
+{
+	struct mmc_host *host = dev->priv;
+	u32 sdi_u32;
+
+	host->base = (struct sdi_registers *)CONFIG_MMC_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 = 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_MMCI_CLOCK_FREQ;
+
+	return 0;
+}
+
+int mmci_init(void)
+{
+	int error;
+	struct mmc *dev;
+
+	dev = alloc_mmc_struct();
+	if (!dev)
+		return -1;
+
+	error = mmc_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/mmci.h b/drivers/mmc/mmci.h
new file mode 100644
index 0000000..ad82e61
--- /dev/null
+++ b/drivers/mmc/mmci.h
@@ -0,0 +1,181 @@
+/*
+ * 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 __MMC_NOMADIK_H__
+#define __MMC_NOMADIK_H__
+
+#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 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
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH 3/3] ARMV7: Vexpress: Add MMC support
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
  2011-02-25  2:35 ` [U-Boot] [PATCH 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
@ 2011-02-25  2:35 ` matt.waddel at linaro.org
  2011-02-25  3:02 ` [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress Reinhard Meyer
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-02-25  2:35 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Added the board specific definitions to use the MMCI device.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +++++++++
 include/configs/ca9x4_ct_vxp.h       |    4 ++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c
index ce1be1e..73cea1c 100644
--- a/board/armltd/vexpress/ca9x4_ct_vxp.c
+++ b/board/armltd/vexpress/ca9x4_ct_vxp.c
@@ -86,6 +86,15 @@ int board_eth_init(bd_t *bis)
 	return rc;
 }
 
+int cpu_mmc_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_MMCI
+	rc = mmci_init(bis);
+#endif
+	return rc;
+}
+
 static void flash__init(void)
 {
 	/* Setup the sytem control register to allow writing to flash */
diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 63f003d..47a3bfc 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -86,6 +86,10 @@
 #define CONFIG_MMC			1
 #define CONFIG_CMD_MMC
 #define CONFIG_GENERIC_MMC
+#define CONFIG_MMCI
+#define CONFIG_MMC_BASE			0x10005000
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT	127
+#define CONFIG_MMCI_CLOCK_FREQ		6250000
 
 /* BOOTP options */
 #define CONFIG_BOOTP_BOOTFILESIZE
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (2 preceding siblings ...)
  2011-02-25  2:35 ` [U-Boot] [PATCH 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
@ 2011-02-25  3:02 ` Reinhard Meyer
  2011-02-28 20:55   ` John Rigby
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 " matt.waddel at linaro.org
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: Reinhard Meyer @ 2011-02-25  3:02 UTC (permalink / raw)
  To: u-boot

Dear matt.waddel at linaro.org,
> From: Matt Waddel<matt.waddel@linaro.org>
>
> These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
> The Versatile Express was the test platform for these changes.
>
> Matt Waddel (3):
>    MMC: Max blocks value adjustable
>    MMC: Add support for PL180 ARM mmc device
>    ARMV7: Vexpress: Add MMC support
>
>   board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
>   drivers/mmc/Makefile                 |    1 +
>   drivers/mmc/mmc.c                    |   19 +-
>   drivers/mmc/mmci.c                   |  452 ++++++++++++++++++++++++++++++++++
>   drivers/mmc/mmci.h                   |  181 ++++++++++++++

I would expect something more descriptive like <hardware>_mmc.[ch] here.
mmci.[ch] does not lead one to think its a hardware specific driver, even less for
what specific hardware it is.
The same is true for the exported function name "mmci_init", the macro CONFIG_MMCI etc.

Then, in patch 2/3:

+int mmci_init(void)

but in patch 3/3:

+	rc = mmci_init(bis);

Seems you should add a prototype to include/mmc.h to detect such mistakes ;)

Best Regards,
Reinhard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress
  2011-02-25  3:02 ` [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress Reinhard Meyer
@ 2011-02-28 20:55   ` John Rigby
  0 siblings, 0 replies; 25+ messages in thread
From: John Rigby @ 2011-02-28 20:55 UTC (permalink / raw)
  To: u-boot

Reinhard,
On Thu, Feb 24, 2011 at 8:02 PM, Reinhard Meyer
<u-boot@emk-elektronik.de> wrote:
> Dear matt.waddel at linaro.org,
>> From: Matt Waddel<matt.waddel@linaro.org>
>>
>> These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
>> The Versatile Express was the test platform for these changes.
>>
>> Matt Waddel (3):
>> ? ?MMC: Max blocks value adjustable
>> ? ?MMC: Add support for PL180 ARM mmc device
>> ? ?ARMV7: Vexpress: Add MMC support
>>
>> ? board/armltd/vexpress/ca9x4_ct_vxp.c | ? ?9 +
>> ? drivers/mmc/Makefile ? ? ? ? ? ? ? ? | ? ?1 +
>> ? drivers/mmc/mmc.c ? ? ? ? ? ? ? ? ? ?| ? 19 +-
>> ? drivers/mmc/mmci.c ? ? ? ? ? ? ? ? ? | ?452 ++++++++++++++++++++++++++++++++++
>> ? drivers/mmc/mmci.h ? ? ? ? ? ? ? ? ? | ?181 ++++++++++++++
>
> I would expect something more descriptive like <hardware>_mmc.[ch] here.
> mmci.[ch] does not lead one to think its a hardware specific driver, even less for
> what specific hardware it is.
> The same is true for the exported function name "mmci_init", the macro CONFIG_MMCI etc.
The file in the linux kernel is mmci.c.  One could argue that keeping
it the same as the kernel is a good thing.  If it needs to be changed,
I would vote for arm_mmci.c.

The config option in the kernel is CONFIG_MMC_ARMMMCI so I would vote
for that as the config option in u-boot.

br,
John

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 0/3] Add support for the MMC device to the vexpress
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (3 preceding siblings ...)
  2011-02-25  3:02 ` [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress Reinhard Meyer
@ 2011-03-01  0:05 ` matt.waddel at linaro.org
  2011-03-01  5:58   ` Reinhard Meyer
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-01  0:05 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
The Versatile Express was the test platform for these changes.

---
Change log:

v2 - Rename patch items to a more descriptive name (ie. mmci -> arm_mmci)
     Fixed conflicting fuction call and added prototype to arm_mmci.h
     (Note: Patch 1/3 did not change with these corrections)

Matt Waddel (3):
  MMC: Max blocks value adjustable
  MMC: Add support for PL180 ARM mmc device
  ARMV7: Vexpress: Add MMC support

 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
 drivers/mmc/Makefile                 |    1 +
 drivers/mmc/arm_mmci.c               |  452 ++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_mmci.h               |  183 ++++++++++++++
 drivers/mmc/mmc.c                    |   19 +-
 include/configs/ca9x4_ct_vxp.h       |    4 +
 6 files changed, 658 insertions(+), 10 deletions(-)
 create mode 100644 drivers/mmc/arm_mmci.c
 create mode 100644 drivers/mmc/arm_mmci.h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 2/3] MMC: Add support for PL180 ARM mmc device
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (4 preceding siblings ...)
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 " matt.waddel at linaro.org
@ 2011-03-01  0:05 ` matt.waddel at linaro.org
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-01  0:05 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Add support for the ARM PrimeCell MultiMedia Interface - PL180.
Ported from original device driver written by ST-Ericsson.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/Makefile   |    1 +
 drivers/mmc/arm_mmci.c |  452 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_mmci.h |  183 +++++++++++++++++++
 3 files changed, 636 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/arm_mmci.c
 create mode 100644 drivers/mmc/arm_mmci.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 3496f0a..7f365b4 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
+COBJS-$(CONFIG_ARM_MMCI) += arm_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_mmci.c b/drivers/mmc/arm_mmci.c
new file mode 100644
index 0000000..8380138
--- /dev/null
+++ b/drivers/mmc/arm_mmci.c
@@ -0,0 +1,452 @@
+/*
+ * 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_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 convert_from_bytes_to_power_of_two(unsigned int x)
+{
+	int y = 0;
+	y = (x & 0xAAAA) ? 1 : 0;
+	y |= ((x & 0xCCCC) ? 1 : 0) << 1;
+	y |= ((x & 0xF0F0) ? 1 : 0) << 2;
+	y |= ((x & 0xFF00) ? 1 : 0) << 3;
+
+	return y;
+}
+
+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 = convert_from_bytes_to_power_of_two(data->blocksize);
+	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_mmci_host_init(struct mmc *dev)
+{
+	struct mmc_host *host = dev->priv;
+	u32 sdi_u32;
+
+	host->base = (struct sdi_registers *)CONFIG_ARM_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_MMCI_CLOCK_FREQ;
+
+	return 0;
+}
+
+int arm_mmci_init(void)
+{
+	int error;
+	struct mmc *dev;
+
+	dev = alloc_mmc_struct();
+	if (!dev)
+		return -1;
+
+	error = arm_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_mmci.h b/drivers/mmc/arm_mmci.h
new file mode 100644
index 0000000..b790f03
--- /dev/null
+++ b/drivers/mmc/arm_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 __MMC_NOMADIK_H__
+#define __MMC_NOMADIK_H__
+
+int 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
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 3/3] ARMV7: Vexpress: Add MMC support
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (5 preceding siblings ...)
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
@ 2011-03-01  0:05 ` matt.waddel at linaro.org
  2011-03-03  5:22 ` [U-Boot] [PATCH V3 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-01  0:05 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Added the board specific definitions to use the MMCI device.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +++++++++
 include/configs/ca9x4_ct_vxp.h       |    4 ++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c
index ce1be1e..92cb6be 100644
--- a/board/armltd/vexpress/ca9x4_ct_vxp.c
+++ b/board/armltd/vexpress/ca9x4_ct_vxp.c
@@ -86,6 +86,15 @@ int board_eth_init(bd_t *bis)
 	return rc;
 }
 
+int cpu_mmc_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_ARM_MMCI
+	rc = arm_mmci_init();
+#endif
+	return rc;
+}
+
 static void flash__init(void)
 {
 	/* Setup the sytem control register to allow writing to flash */
diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 63f003d..52fb5df 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -86,6 +86,10 @@
 #define CONFIG_MMC			1
 #define CONFIG_CMD_MMC
 #define CONFIG_GENERIC_MMC
+#define CONFIG_ARM_MMCI
+#define CONFIG_ARM_MMCI_BASE		0x10005000
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT	127
+#define CONFIG_ARM_MMCI_CLOCK_FREQ	6250000
 
 /* BOOTP options */
 #define CONFIG_BOOTP_BOOTFILESIZE
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 0/3] Add support for the MMC device to the vexpress
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 " matt.waddel at linaro.org
@ 2011-03-01  5:58   ` Reinhard Meyer
  2011-03-01 17:08     ` Matt Waddel
  0 siblings, 1 reply; 25+ messages in thread
From: Reinhard Meyer @ 2011-03-01  5:58 UTC (permalink / raw)
  To: u-boot

Dear matt.waddel,
> From: Matt Waddel<matt.waddel@linaro.org>
>
> These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
> The Versatile Express was the test platform for these changes.
>
> ---
> Change log:
>
> v2 - Rename patch items to a more descriptive name (ie. mmci ->  arm_mmci)
>       Fixed conflicting fuction call and added prototype to arm_mmci.h
"function"
>       (Note: Patch 1/3 did not change with these corrections)
>
> Matt Waddel (3):
>    MMC: Max blocks value adjustable
>    MMC: Add support for PL180 ARM mmc device
>    ARMV7: Vexpress: Add MMC support
>
>   board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
>   drivers/mmc/Makefile                 |    1 +
>   drivers/mmc/arm_mmci.c               |  452 ++++++++++++++++++++++++++++++++++
>   drivers/mmc/arm_mmci.h               |  183 ++++++++++++++
>   drivers/mmc/mmc.c                    |   19 +-
>   include/configs/ca9x4_ct_vxp.h       |    4 +
>   6 files changed, 658 insertions(+), 10 deletions(-)
>   create mode 100644 drivers/mmc/arm_mmci.c
>   create mode 100644 drivers/mmc/arm_mmci.h

Sorry, my original comment still holds true for the naming,
now the name suggests that this driver is generic to ARM devices,
which clearly is not true.

Can you list which devices have a MMCI that is covered by this
driver? PL180 only? Or a series of PLxxx? It should be
possible to find a naming that is more descriptive than "arm".

(That such a generic name slipped into the kernel must not
imply we have to make the same mistake in u-boot)

Best Regards,
Reinhard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 0/3] Add support for the MMC device to the vexpress
  2011-03-01  5:58   ` Reinhard Meyer
@ 2011-03-01 17:08     ` Matt Waddel
  2011-03-01 20:28       ` Reinhard Meyer
  0 siblings, 1 reply; 25+ messages in thread
From: Matt Waddel @ 2011-03-01 17:08 UTC (permalink / raw)
  To: u-boot

Hi Reinhard,

On 02/28/2011 10:58 PM, Reinhard Meyer wrote:
> Dear matt.waddel,
>> From: Matt Waddel<matt.waddel@linaro.org>
>>
<snip>
> Sorry, my original comment still holds true for the naming,
> now the name suggests that this driver is generic to ARM devices,
> which clearly is not true.

Correct. However, this hardware device was developed by ARM (the
company). As far as I know the other ARM mmc drivers, like the
omap3_mmc, are not. So that would be the difference between the
naming of these drivers.

I don't feel like this driver should be named after a particular
platform like vexpress, since this driver could be used in any
ARM hardware.

> 
> Can you list which devices have a MMCI that is covered by this
> driver? PL180 only? Or a series of PLxxx? It should be
> possible to find a naming that is more descriptive than "arm".

The PL180 is the name assigned to the hardware in the SOC.
Here is the description of device from the 1st paragraph in
the manual:

1.1 About the ARM PrimeCell Multimedia Card Interface (PL180)
   The PrimeCell Multimedia Card Interface (MCI) is an Advanced
Microcontroller Bus Architecture(AMBA) compliant, System-on-a-Chip
(SoC) peripheral that is developed, tested, and licensed by ARM.
----

As far as other platforms that use this hardware, it is in some
of the other ARM EVMs and some STEricsson platforms like the u300
and u8500.

> 
> (That such a generic name slipped into the kernel must not
> imply we have to make the same mistake in u-boot)

I agree. However, it would be nice to have a bit of a link between
the device in the kernel and the one in u-boot and I didn't think
having "_mmci" in the name would be too objectionable.

Would pl180_mmci.c work? or how about arm_pl180_mmc.c? I'm open to
other suggestions.

Best regards,
Matt

> 
> Best Regards,
> Reinhard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V2 0/3] Add support for the MMC device to the vexpress
  2011-03-01 17:08     ` Matt Waddel
@ 2011-03-01 20:28       ` Reinhard Meyer
  0 siblings, 0 replies; 25+ messages in thread
From: Reinhard Meyer @ 2011-03-01 20:28 UTC (permalink / raw)
  To: u-boot

Hello Matt Waddel,
>> Sorry, my original comment still holds true for the naming,
>> now the name suggests that this driver is generic to ARM devices,
>> which clearly is not true.
>
> Correct. However, this hardware device was developed by ARM (the
> company). As far as I know the other ARM mmc drivers, like the
> omap3_mmc, are not. So that would be the difference between the
> naming of these drivers.

I see. The "problem" is that ARM is a company, an architecture, and
now even an IP manufacturer...

>
> I don't feel like this driver should be named after a particular
> platform like vexpress, since this driver could be used in any
> ARM hardware.

Correct.

>
>>
>> Can you list which devices have a MMCI that is covered by this
>> driver? PL180 only? Or a series of PLxxx? It should be
>> possible to find a naming that is more descriptive than "arm".
>
> The PL180 is the name assigned to the hardware in the SOC.
> Here is the description of device from the 1st paragraph in
> the manual:
>
> 1.1 About the ARM PrimeCell Multimedia Card Interface (PL180)
>     The PrimeCell Multimedia Card Interface (MCI) is an Advanced
> Microcontroller Bus Architecture(AMBA) compliant, System-on-a-Chip
> (SoC) peripheral that is developed, tested, and licensed by ARM.
> ----
>
> As far as other platforms that use this hardware, it is in some
> of the other ARM EVMs and some STEricsson platforms like the u300
> and u8500.
>
>>
>> (That such a generic name slipped into the kernel must not
>> imply we have to make the same mistake in u-boot)
>
> I agree. However, it would be nice to have a bit of a link between
> the device in the kernel and the one in u-boot and I didn't think
> having "_mmci" in the name would be too objectionable.
>
> Would pl180_mmci.c work? or how about arm_pl180_mmc.c? I'm open to
> other suggestions.

Yes, after what you have described, is it to be expected that it is
always designated as PL180 when licensed and used by a SoC nanufacturer?
"arm_pl180_mmci" would be best then, I think. That leaves the namespace
open for other "arm_*_mmci" controllers that might appear in the future.

Best regards,
Reinhard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V3 0/3] Add support for the MMC device to the vexpress
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (6 preceding siblings ...)
  2011-03-01  0:05 ` [U-Boot] [PATCH V2 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
@ 2011-03-03  5:22 ` matt.waddel at linaro.org
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
  9 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-03  5:22 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
The Versatile Express was the test platform for these changes.

---
Change log:

v2 - Rename patch items to a more descriptive name (ie. mmci -> arm_mmci)
     Fixed conflicting fuction call and added prototype to arm_mmci.h

v3 - Rename patch items (arm_mmci -> arm_pl180_mmci)
     (Note: Patch 1/3 still did not change with these corrections)

Matt Waddel (3):
  MMC: Max blocks value adjustable
  MMC: Add support for PL180 ARM mmc device
  ARMV7: Vexpress: Add MMC support

 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
 drivers/mmc/Makefile                 |    1 +
 drivers/mmc/arm_pl180_mmci.c         |  452 ++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_pl180_mmci.h         |  183 ++++++++++++++
 drivers/mmc/mmc.c                    |   19 +-
 include/configs/ca9x4_ct_vxp.h       |    4 +
 6 files changed, 658 insertions(+), 10 deletions(-)
 create mode 100644 drivers/mmc/arm_pl180_mmci.c
 create mode 100644 drivers/mmc/arm_pl180_mmci.h

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (7 preceding siblings ...)
  2011-03-03  5:22 ` [U-Boot] [PATCH V3 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
@ 2011-03-03  5:22 ` matt.waddel at linaro.org
  2011-04-13 11:04   ` Andy Fleming
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
  9 siblings, 1 reply; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-03  5:22 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Add support for the ARM PrimeCell MultiMedia Interface - PL180.
Ported from original device driver written by ST-Ericsson.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/Makefile         |    1 +
 drivers/mmc/arm_pl180_mmci.c |  452 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_pl180_mmci.h |  183 +++++++++++++++++
 3 files changed, 636 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/arm_pl180_mmci.c
 create mode 100644 drivers/mmc/arm_pl180_mmci.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 3496f0a..7b3c319 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.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 0000000..9b60e4f
--- /dev/null
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -0,0 +1,452 @@
+/*
+ * 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 convert_from_bytes_to_power_of_two(unsigned int x)
+{
+	int y = 0;
+	y = (x & 0xAAAA) ? 1 : 0;
+	y |= ((x & 0xCCCC) ? 1 : 0) << 1;
+	y |= ((x & 0xF0F0) ? 1 : 0) << 2;
+	y |= ((x & 0xFF00) ? 1 : 0) << 3;
+
+	return y;
+}
+
+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 = convert_from_bytes_to_power_of_two(data->blocksize);
+	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 0000000..42fbe3e
--- /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
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
                   ` (8 preceding siblings ...)
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
@ 2011-03-03  5:22 ` matt.waddel at linaro.org
  2011-04-13 11:09   ` Andy Fleming
  2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  9 siblings, 2 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-03-03  5:22 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Added the board specific definitions to use the MMCI device.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +++++++++
 include/configs/ca9x4_ct_vxp.h       |    4 ++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c
index ce1be1e..3566b95 100644
--- a/board/armltd/vexpress/ca9x4_ct_vxp.c
+++ b/board/armltd/vexpress/ca9x4_ct_vxp.c
@@ -86,6 +86,15 @@ int board_eth_init(bd_t *bis)
 	return rc;
 }
 
+int cpu_mmc_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_ARM_PL180_MMCI
+	rc = arm_pl180_mmci_init();
+#endif
+	return rc;
+}
+
 static void flash__init(void)
 {
 	/* Setup the sytem control register to allow writing to flash */
diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 63f003d..4ab58c0 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -86,6 +86,10 @@
 #define CONFIG_MMC			1
 #define CONFIG_CMD_MMC
 #define CONFIG_GENERIC_MMC
+#define CONFIG_ARM_PL180_MMCI
+#define CONFIG_ARM_PL180_MMCI_BASE	0x10005000
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT	127
+#define CONFIG_ARM_PL180_MMCI_CLOCK_FREQ 6250000
 
 /* BOOTP options */
 #define CONFIG_BOOTP_BOOTFILESIZE
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
@ 2011-04-13 11:04   ` Andy Fleming
  0 siblings, 0 replies; 25+ messages in thread
From: Andy Fleming @ 2011-04-13 11:04 UTC (permalink / raw)
  To: u-boot

On Wed, Mar 2, 2011 at 11:22 PM,  <matt.waddel@linaro.org> wrote:

> +
> +static int convert_from_bytes_to_power_of_two(unsigned int x)
> +{
> + ? ? ? int y = 0;
> + ? ? ? y = (x & 0xAAAA) ? 1 : 0;
> + ? ? ? y |= ((x & 0xCCCC) ? 1 : 0) << 1;
> + ? ? ? y |= ((x & 0xF0F0) ? 1 : 0) << 2;
> + ? ? ? y |= ((x & 0xFF00) ? 1 : 0) << 3;
> +
> + ? ? ? return y;
> +}


Let's not try to be this clever.  U-Boot already has a function that
tells you which power of two a number corresponds to.  Unless the
caller of this will be highly sensitive to several cycles that you may
gain from knowing that the input is already a power-of-two, there's
just no cause to creating a separate implementation of ffs().

Other than that, it looks fine, and as soon as you respin, I'll add it
to the mmc tree.

Andy

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
@ 2011-04-13 11:09   ` Andy Fleming
  2011-04-16 21:53     ` Matt Waddel
  2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  1 sibling, 1 reply; 25+ messages in thread
From: Andy Fleming @ 2011-04-13 11:09 UTC (permalink / raw)
  To: u-boot

On Wed, Mar 2, 2011 at 11:22 PM,  <matt.waddel@linaro.org> wrote:
> From: Matt Waddel <matt.waddel@linaro.org>
>
> Added the board specific definitions to use the MMCI device.
>
> Signed-off-by: Matt Waddel <matt.waddel@linaro.org>

Looks fine to me.  I can apply this to my tree if that's fine with the
maintainer.  If not, I'm also OK if the maintainer wants to pull in
the driver patch (with the previously-mentioned small change).

Either way:
Acked-by: Andy Fleming <afleming@freescale.com>

Andy

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-04-13 11:09   ` Andy Fleming
@ 2011-04-16 21:53     ` Matt Waddel
  2011-04-28 18:46       ` John Rigby
  0 siblings, 1 reply; 25+ messages in thread
From: Matt Waddel @ 2011-04-16 21:53 UTC (permalink / raw)
  To: u-boot

On 04/13/2011 05:09 AM, Andy Fleming wrote:
> On Wed, Mar 2, 2011 at 11:22 PM,  <matt.waddel@linaro.org> wrote:
>> From: Matt Waddel <matt.waddel@linaro.org>
>>
>> Added the board specific definitions to use the MMCI device.
>>
>> Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
> 
> Looks fine to me.  I can apply this to my tree if that's fine with the
> maintainer.  If not, I'm also OK if the maintainer wants to pull in
> the driver patch (with the previously-mentioned small change).

Hi Andy,

I made the ffs() change you suggested and have posted a 4th
version of the 3 patches (even though the 2nd one was the only
one that changed, I wanted to make sure they were all still in
sync with the repository).

If you could apply these to your tree that would be great.

> 
> Either way:
> Acked-by: Andy Fleming <afleming@freescale.com>

Thanks,
Matt

> 
> Andy
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress
  2011-03-03  5:22 ` [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
  2011-04-13 11:09   ` Andy Fleming
@ 2011-04-16 21:54   ` matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
                       ` (2 more replies)
  1 sibling, 3 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-04-16 21:54 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

These patches add support for the ARM PrimeCell PL180 MultiMedia Interface.
The Versatile Express was the test platform for these changes.

---
Change log:

v2 - Rename patch items to a more descriptive name (ie. mmci -> arm_mmci)
     Fixed conflicting fuction call and added prototype to arm_mmci.h

v3 - Rename patch items (arm_mmci -> arm_pl180_mmci)
     (Note: Patch 1/3 still did not change with these corrections)

v4 - Removed convert_from_bytes_to_power_of_two() routine and used generic ffs
     call instead. (Feedback from Andy Fleming.)

Matt Waddel (3):
  MMC: Max blocks value adjustable
  MMC: Add support for PL180 ARM mmc device
  ARMV7: Vexpress: Add MMC support

 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +
 drivers/mmc/Makefile                 |    1 +
 drivers/mmc/arm_pl180_mmci.c         |  441 ++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_pl180_mmci.h         |  183 ++++++++++++++
 drivers/mmc/mmc.c                    |   19 +-
 include/configs/ca9x4_ct_vxp.h       |    4 +
 6 files changed, 647 insertions(+), 10 deletions(-)
 create mode 100644 drivers/mmc/arm_pl180_mmci.c
 create mode 100644 drivers/mmc/arm_pl180_mmci.h

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V4 1/3] MMC: Max blocks value adjustable
  2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
@ 2011-04-16 21:54     ` matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
  2 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-04-16 21:54 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

The maximum blocks value was hardcoded to 65535 due to a 16 bit
register length.  The value can change for different platforms.
This patch makes the default the current value of 65535, but it
is configurable for other platforms.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/mmc.c |   19 +++++++++----------
 1 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6805b33..d69eaa1 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -33,6 +33,11 @@
 #include <mmc.h>
 #include <div64.h>
 
+/* Set block count limit because of 16 bit register limit on some hardware*/
+#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
+#endif
+
 static struct list_head mmc_devices;
 static int cur_dev_num = -1;
 
@@ -139,11 +144,8 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
 		return 0;
 
 	do {
-		/*
-		 * The 65535 constraint comes from some hardware has
-		 * only 16 bit width block number counter
-		 */
-		cur = (blocks_todo > 65535) ? 65535 : blocks_todo;
+		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
+		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
 		if(mmc_write_blocks(mmc, start, cur, src) != cur)
 			return 0;
 		blocks_todo -= cur;
@@ -215,11 +217,8 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
 		return 0;
 
 	do {
-		/*
-		 * The 65535 constraint comes from some hardware has
-		 * only 16 bit width block number counter
-		 */
-		cur = (blocks_todo > 65535) ? 65535 : blocks_todo;
+		cur = (blocks_todo > CONFIG_SYS_MMC_MAX_BLK_COUNT) ?
+		       CONFIG_SYS_MMC_MAX_BLK_COUNT : blocks_todo;
 		if(mmc_read_blocks(mmc, dst, start, cur) != cur)
 			return 0;
 		blocks_todo -= cur;
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V4 2/3] MMC: Add support for PL180 ARM mmc device
  2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
@ 2011-04-16 21:54     ` matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
  2 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-04-16 21:54 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Add support for the ARM PrimeCell MultiMedia Interface - PL180.
Ported from original device driver written by ST-Ericsson.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 drivers/mmc/Makefile         |    1 +
 drivers/mmc/arm_pl180_mmci.c |  441 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/arm_pl180_mmci.h |  183 +++++++++++++++++
 3 files changed, 625 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mmc/arm_pl180_mmci.c
 create mode 100644 drivers/mmc/arm_pl180_mmci.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 3496f0a..7b3c319 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.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 0000000..245f482
--- /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 0000000..42fbe3e
--- /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
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH V4 3/3] ARMV7: Vexpress: Add MMC support
  2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
  2011-04-16 21:54     ` [U-Boot] [PATCH V4 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
@ 2011-04-16 21:54     ` matt.waddel at linaro.org
  2 siblings, 0 replies; 25+ messages in thread
From: matt.waddel at linaro.org @ 2011-04-16 21:54 UTC (permalink / raw)
  To: u-boot

From: Matt Waddel <matt.waddel@linaro.org>

Added the board specific definitions to use the MMCI device.

Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
---
 board/armltd/vexpress/ca9x4_ct_vxp.c |    9 +++++++++
 include/configs/ca9x4_ct_vxp.h       |    4 ++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c
index ce1be1e..3566b95 100644
--- a/board/armltd/vexpress/ca9x4_ct_vxp.c
+++ b/board/armltd/vexpress/ca9x4_ct_vxp.c
@@ -86,6 +86,15 @@ int board_eth_init(bd_t *bis)
 	return rc;
 }
 
+int cpu_mmc_init(bd_t *bis)
+{
+	int rc = 0;
+#ifdef CONFIG_ARM_PL180_MMCI
+	rc = arm_pl180_mmci_init();
+#endif
+	return rc;
+}
+
 static void flash__init(void)
 {
 	/* Setup the sytem control register to allow writing to flash */
diff --git a/include/configs/ca9x4_ct_vxp.h b/include/configs/ca9x4_ct_vxp.h
index 63f003d..4ab58c0 100644
--- a/include/configs/ca9x4_ct_vxp.h
+++ b/include/configs/ca9x4_ct_vxp.h
@@ -86,6 +86,10 @@
 #define CONFIG_MMC			1
 #define CONFIG_CMD_MMC
 #define CONFIG_GENERIC_MMC
+#define CONFIG_ARM_PL180_MMCI
+#define CONFIG_ARM_PL180_MMCI_BASE	0x10005000
+#define CONFIG_SYS_MMC_MAX_BLK_COUNT	127
+#define CONFIG_ARM_PL180_MMCI_CLOCK_FREQ 6250000
 
 /* BOOTP options */
 #define CONFIG_BOOTP_BOOTFILESIZE
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-04-16 21:53     ` Matt Waddel
@ 2011-04-28 18:46       ` John Rigby
  2011-04-28 18:57         ` Andy Fleming
  0 siblings, 1 reply; 25+ messages in thread
From: John Rigby @ 2011-04-28 18:46 UTC (permalink / raw)
  To: u-boot

On Sat, Apr 16, 2011 at 3:53 PM, Matt Waddel <matt.waddel@canonical.com> wrote:
> On 04/13/2011 05:09 AM, Andy Fleming wrote:
>> On Wed, Mar 2, 2011 at 11:22 PM, ?<matt.waddel@linaro.org> wrote:
>>> From: Matt Waddel <matt.waddel@linaro.org>
>>>
>>> Added the board specific definitions to use the MMCI device.
>>>
>>> Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
>>
>> Looks fine to me. ?I can apply this to my tree if that's fine with the
>> maintainer. ?If not, I'm also OK if the maintainer wants to pull in
>> the driver patch (with the previously-mentioned small change).
>
> Hi Andy,
>
> I made the ffs() change you suggested and have posted a 4th
> version of the 3 patches (even though the 2nd one was the only
> one that changed, I wanted to make sure they were all still in
> sync with the repository).
>
> If you could apply these to your tree that would be great.
>
>>
>> Either way:
>> Acked-by: Andy Fleming <afleming@freescale.com>
>
> Thanks,
> Matt
>
>>
>> Andy
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>

Andy, Matt:

What is the plan for getting the pl180 mmc driver commited?  I need it
in before my U8500 board patches can be commited.

Thanks,
John

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-04-28 18:46       ` John Rigby
@ 2011-04-28 18:57         ` Andy Fleming
  2011-04-28 19:49           ` John Rigby
  0 siblings, 1 reply; 25+ messages in thread
From: Andy Fleming @ 2011-04-28 18:57 UTC (permalink / raw)
  To: u-boot

It's on my todo list for today

On Apr 28, 2011, at 1:46 PM, John Rigby wrote:

> On Sat, Apr 16, 2011 at 3:53 PM, Matt Waddel <matt.waddel@canonical.com> wrote:
>> On 04/13/2011 05:09 AM, Andy Fleming wrote:
>>> On Wed, Mar 2, 2011 at 11:22 PM,  <matt.waddel@linaro.org> wrote:
>>>> From: Matt Waddel <matt.waddel@linaro.org>
>>>> 
>>>> Added the board specific definitions to use the MMCI device.
>>>> 
>>>> Signed-off-by: Matt Waddel <matt.waddel@linaro.org>
>>> 
>>> Looks fine to me.  I can apply this to my tree if that's fine with the
>>> maintainer.  If not, I'm also OK if the maintainer wants to pull in
>>> the driver patch (with the previously-mentioned small change).
>> 
>> Hi Andy,
>> 
>> I made the ffs() change you suggested and have posted a 4th
>> version of the 3 patches (even though the 2nd one was the only
>> one that changed, I wanted to make sure they were all still in
>> sync with the repository).
>> 
>> If you could apply these to your tree that would be great.
>> 
>>> 
>>> Either way:
>>> Acked-by: Andy Fleming <afleming@freescale.com>
>> 
>> Thanks,
>> Matt
>> 
>>> 
>>> Andy
>>> _______________________________________________
>>> U-Boot mailing list
>>> U-Boot at lists.denx.de
>>> http://lists.denx.de/mailman/listinfo/u-boot
>> 
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot
>> 
> 
> Andy, Matt:
> 
> What is the plan for getting the pl180 mmc driver commited?  I need it
> in before my U8500 board patches can be commited.
> 
> Thanks,
> John
> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support
  2011-04-28 18:57         ` Andy Fleming
@ 2011-04-28 19:49           ` John Rigby
  0 siblings, 0 replies; 25+ messages in thread
From: John Rigby @ 2011-04-28 19:49 UTC (permalink / raw)
  To: u-boot

On Thu, Apr 28, 2011 at 12:57 PM, Andy Fleming <afleming@freescale.com> wrote:
> It's on my todo list for today
Thanks!

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2011-04-28 19:49 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-25  2:35 [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
2011-02-25  2:35 ` [U-Boot] [PATCH 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
2011-02-25  2:35 ` [U-Boot] [PATCH 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
2011-02-25  2:35 ` [U-Boot] [PATCH 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
2011-02-25  3:02 ` [U-Boot] [PATCH 0/3] Add support for the MMC device to the vexpress Reinhard Meyer
2011-02-28 20:55   ` John Rigby
2011-03-01  0:05 ` [U-Boot] [PATCH V2 " matt.waddel at linaro.org
2011-03-01  5:58   ` Reinhard Meyer
2011-03-01 17:08     ` Matt Waddel
2011-03-01 20:28       ` Reinhard Meyer
2011-03-01  0:05 ` [U-Boot] [PATCH V2 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
2011-03-01  0:05 ` [U-Boot] [PATCH V2 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
2011-03-03  5:22 ` [U-Boot] [PATCH V3 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
2011-03-03  5:22 ` [U-Boot] [PATCH v3 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
2011-04-13 11:04   ` Andy Fleming
2011-03-03  5:22 ` [U-Boot] [PATCH v3 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org
2011-04-13 11:09   ` Andy Fleming
2011-04-16 21:53     ` Matt Waddel
2011-04-28 18:46       ` John Rigby
2011-04-28 18:57         ` Andy Fleming
2011-04-28 19:49           ` John Rigby
2011-04-16 21:54   ` [U-Boot] [PATCH V4 0/3] Add support for the MMC device to the vexpress matt.waddel at linaro.org
2011-04-16 21:54     ` [U-Boot] [PATCH V4 1/3] MMC: Max blocks value adjustable matt.waddel at linaro.org
2011-04-16 21:54     ` [U-Boot] [PATCH V4 2/3] MMC: Add support for PL180 ARM mmc device matt.waddel at linaro.org
2011-04-16 21:54     ` [U-Boot] [PATCH V4 3/3] ARMV7: Vexpress: Add MMC support matt.waddel at linaro.org

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.