[U-Boot] [PATCH 09/11] u8500: Separating mmc config parameters from driver

mathieu.poirier at linaro.org mathieu.poirier at linaro.org
Mon Jun 18 18:25:34 CEST 2012


From: John Rigby <john.rigby at linaro.org>

Configuration in vexpress and u8500.v1 is different from what
is needed in u8500.v2.  As such, card configuration specifics need
to reside in the board file rather than the driver.

Signed-off-by: John Rigby <john.rigby at linaro.org>
Signed-off-by: Mathieu Poirier <mathieu.poirier at linaro.org>
---
 board/armltd/vexpress/ca9x4_ct_vxp.c  |   21 +++++-
 board/st-ericsson/snowball/snowball.c |   92 ++++++++++++++++++++++-
 board/st-ericsson/u8500/u8500_href.c  |   22 +++++-
 drivers/mmc/arm_pl180_mmci.c          |  132 +++++++++++++--------------------
 drivers/mmc/arm_pl180_mmci.h          |   27 ++++++-
 include/configs/snowball.h            |    8 ++
 6 files changed, 214 insertions(+), 88 deletions(-)

diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c
index 0b36d12..d5e109e 100644
--- a/board/armltd/vexpress/ca9x4_ct_vxp.c
+++ b/board/armltd/vexpress/ca9x4_ct_vxp.c
@@ -33,6 +33,8 @@
  * MA 02111-1307 USA
  */
 #include <common.h>
+#include <malloc.h>
+#include <errno.h>
 #include <netdev.h>
 #include <asm/io.h>
 #include <asm/arch/systimer.h>
@@ -90,8 +92,25 @@ int board_eth_init(bd_t *bis)
 int cpu_mmc_init(bd_t *bis)
 {
 	int rc = 0;
+	(void) bis;
 #ifdef CONFIG_ARM_PL180_MMCI
-	rc = arm_pl180_mmci_init();
+	struct pl180_mmc_host *host;
+
+	host = malloc(sizeof(struct pl180_mmc_host));
+	if (!host)
+		return -ENOMEM;
+	memset(host, 0, sizeof(*host));
+
+	strcpy(host->name, "MMC");
+	host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE;
+	host->pwr_init = INIT_PWR;
+	host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN;
+	host->voltages = VOLTAGE_WINDOW_MMC;
+	host->caps = 0;
+	host->clock_in = ARM_MCLK;
+	host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1));
+	host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ;
+	rc = arm_pl180_mmci_init(host);
 #endif
 	return rc;
 }
diff --git a/board/st-ericsson/snowball/snowball.c b/board/st-ericsson/snowball/snowball.c
index 2c01bc1..a44847c 100644
--- a/board/st-ericsson/snowball/snowball.c
+++ b/board/st-ericsson/snowball/snowball.c
@@ -29,6 +29,9 @@
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
 
+#ifdef CONFIG_MMC
+#include "../../../drivers/mmc/arm_pl180_mmci.h"
+#endif
 #include "db8500_pins.h"
 
 /*
@@ -269,9 +272,96 @@ int board_late_init(void)
 	if ((raise_ab8500_gpio16() < 0))
 		printf("error: cant' raise GPIO16\n");
 
+	return 0;
+}
+
 #ifdef CONFIG_MMC
+/*
+ * emmc_host_init - initialize the emmc controller.
+ * Configure GPIO settings, set initial clock and power for emmc slot.
+ * Initialize mmc struct and register with mmc framework.
+ */
+static int emmc_host_init(void)
+{
+	struct pl180_mmc_host *host;
+
+	host = malloc(sizeof(struct pl180_mmc_host));
+	if (!host)
+		return -ENOMEM;
+	memset(host, 0, sizeof(*host));
+
+	host->base = (struct sdi_registers *)CFG_EMMC_BASE;
+	host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
+	host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 |
+				 SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN;
+	strcpy(host->name, "EMMC");
+	host->caps = MMC_MODE_8BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz;
+	host->voltages = VOLTAGE_WINDOW_MMC;
+	host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2);
+	host->clock_max = ARM_MCLK / 2;
+	host->clock_in = ARM_MCLK;
+	host->version2 = 1;
+
+	return arm_pl180_mmci_init(host);
+}
+
+/*
+ * mmc_host_init - initialize the external mmc controller.
+ * Configure GPIO settings, set initial clock and power for mmc slot.
+ * Initialize mmc struct and register with mmc framework.
+ */
+static int mmc_host_init(void)
+{
+	struct pl180_mmc_host *host;
+	u32 sdi_u32;
+
+	host = malloc(sizeof(struct pl180_mmc_host));
+	if (!host)
+		return -ENOMEM;
+	memset(host, 0, sizeof(*host));
+
+	host->base = (struct sdi_registers *)CFG_MMC_BASE;
+	sdi_u32 = 0xBF;
+	writel(sdi_u32, &host->base->power);
+	host->pwr_init = 0xBF;
+	host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 |
+				 SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN;
+	strcpy(host->name, "MMC");
+	host->caps = MMC_MODE_8BIT;
+	host->b_max = 0;
+	host->voltages = VOLTAGE_WINDOW_SD;
+	host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2);
+	host->clock_max = ARM_MCLK / 2;
+	host->clock_in = ARM_MCLK;
+	host->version2 = 1;
+
+	return arm_pl180_mmci_init(host);
+}
+
+/*
+ * board_mmc_init - initialize all the mmc/sd host controllers.
+ * Called by generic mmc framework.
+ */
+int board_mmc_init(bd_t *bis)
+{
+	int error;
+
+	(void) bis;
+
+	error = emmc_host_init();
+	if (error) {
+		printf("emmc_host_init() %d\n", error);
+		return -1;
+	}
+
 	u8500_mmc_power_init();
-#endif /* CONFIG_MMC */
+
+	error = mmc_host_init();
+	if (error) {
+		printf("mmc_host_init() %d\n", error);
+		return -1;
+	}
 
 	return 0;
 }
+#endif /* CONFIG_MMC */
diff --git a/board/st-ericsson/u8500/u8500_href.c b/board/st-ericsson/u8500/u8500_href.c
index e75f8b4..f06120c 100644
--- a/board/st-ericsson/u8500/u8500_href.c
+++ b/board/st-ericsson/u8500/u8500_href.c
@@ -18,6 +18,7 @@
 
 #include <config.h>
 #include <common.h>
+#include <malloc.h>
 #include <i2c.h>
 #include <asm/types.h>
 #include <asm/io.h>
@@ -375,12 +376,27 @@ static int u8500_mmci_board_init(void)
 
 int board_mmc_init(bd_t *bd)
 {
+	struct pl180_mmc_host *host;
+
 	if (u8500_mmci_board_init())
 		return -ENODEV;
 
-	if (arm_pl180_mmci_init())
-		return -ENODEV;
-	return 0;
+	host = malloc(sizeof(struct pl180_mmc_host));
+	if (!host)
+		return -ENOMEM;
+	memset(host, 0, sizeof(*host));
+
+	strcpy(host->name, "MMC");
+	host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE;
+	host->pwr_init = INIT_PWR;
+	host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN;
+	host->voltages = VOLTAGE_WINDOW_MMC;
+	host->caps = 0;
+	host->clock_in = ARM_MCLK;
+	host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1));
+	host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ;
+
+	return arm_pl180_mmci_init(host);
 }
 #endif
 
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index 09d443e..2966520 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -32,14 +32,10 @@
 #include "arm_pl180_mmci.h"
 #include <malloc.h>
 
-struct mmc_host {
-	struct sdi_registers *base;
-};
-
 static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
 {
 	u32 hoststatus, statusmask;
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
 
 	statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
 	if ((cmd->resp_type & MMC_RSP_PRESENT))
@@ -53,8 +49,8 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
 
 	writel(statusmask, &host->base->status_clear);
 	if (hoststatus & SDI_STA_CTIMEOUT) {
-		printf("CMD%d time out\n", cmd->cmdidx);
-		return -ETIMEDOUT;
+		debug("CMD%d time out\n", cmd->cmdidx);
+		return TIMEOUT;
 	} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
 		   (cmd->flags & MMC_RSP_CRC)) {
 		printf("CMD%d CRC error\n", cmd->cmdidx);
@@ -80,7 +76,8 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
 {
 	int result;
 	u32 sdi_cmd = 0;
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
+	u32 lap = 0;
 
 	sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
 
@@ -112,7 +109,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
 {
 	u32 *tempbuff = dest;
 	u64 xfercount = blkcount * blksize;
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
 	u32 status, status_err;
 
 	debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -168,7 +165,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
 	u32 *tempbuff = src;
 	int i;
 	u64 xfercount = blkcount * blksize;
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
 	u32 status, status_err;
 
 	debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -227,14 +224,19 @@ static int do_data_transfer(struct mmc *dev,
 			    struct mmc_data *data)
 {
 	int error = -ETIMEDOUT;
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
 	u32 blksz = 0;
 	u32 data_ctrl = 0;
 	u32 data_len = (u32) (data->blocks * data->blocksize);
 
-	blksz = (ffs(data->blocksize) - 1);
-	data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
-	data_ctrl |= SDI_DCTRL_DTEN;
+	if (!host->version2) {
+		blksz = (ffs(data->blocksize) - 1);
+		data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
+	} else {
+		blksz = data->blocksize;
+		data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
+	}
+	data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
 
 	writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
 	writel(data_len, &host->base->datalength);
@@ -257,7 +259,7 @@ static int do_data_transfer(struct mmc *dev,
 
 		writel(data_ctrl, &host->base->datactrl);
 		error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
-				    (u32)data->blocksize);
+							(u32)data->blocksize);
 	}
 
 	return error;
@@ -280,17 +282,16 @@ static int host_request(struct mmc *dev,
 /* MMC uses open drain drivers in the enumeration phase */
 static int mmc_host_reset(struct mmc *dev)
 {
-	struct mmc_host *host = dev->priv;
-	u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
+	struct pl180_mmc_host *host = dev->priv;
 
-	writel(sdi_u32, &host->base->power);
+	writel(host->pwr_init, &host->base->power);
 
 	return 0;
 }
 
 static void host_set_ios(struct mmc *dev)
 {
-	struct mmc_host *host = dev->priv;
+	struct pl180_mmc_host *host = dev->priv;
 	u32 sdi_clkcr;
 
 	sdi_clkcr = readl(&host->base->clock);
@@ -298,15 +299,26 @@ static void host_set_ios(struct mmc *dev)
 	/* Ramp up the clock rate */
 	if (dev->clock) {
 		u32 clkdiv = 0;
+		u32 tmp_clock;
 
-		if (dev->clock >= dev->f_max)
+		if (dev->clock >= dev->f_max) {
+			clkdiv = 0;
 			dev->clock = dev->f_max;
+		} else {
+			clkdiv = (host->clock_in / dev->clock) - 2;
+		}
 
-		clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1;
+		tmp_clock = host->clock_in / (clkdiv + 2);
+		while (tmp_clock > dev->clock) {
+			clkdiv++;
+			tmp_clock = host->clock_in / (clkdiv + 2);
+		}
 
 		if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
 			clkdiv = SDI_CLKCR_CLKDIV_MASK;
 
+		tmp_clock = host->clock_in / (clkdiv + 2);
+		dev->clock = tmp_clock;
 		sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
 		sdi_clkcr |= clkdiv;
 	}
@@ -322,8 +334,11 @@ static void host_set_ios(struct mmc *dev)
 		case 4:
 			buswidth |= SDI_CLKCR_WIDBUS_4;
 			break;
+		case 8:
+			buswidth |= SDI_CLKCR_WIDBUS_8;
+			break;
 		default:
-			printf("Invalid bus width\n");
+			printf("Invalid bus width: %d\n", dev->bus_width);
 			break;
 		}
 		sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
@@ -334,83 +349,40 @@ static void host_set_ios(struct mmc *dev)
 	udelay(CLK_CHANGE_DELAY);
 }
 
-struct mmc *alloc_mmc_struct(void)
-{
-	struct mmc_host *host = NULL;
-	struct mmc *mmc_device = NULL;
-
-	host = malloc(sizeof(struct mmc_host));
-	if (!host)
-		return NULL;
-
-	mmc_device = malloc(sizeof(struct mmc));
-	if (!mmc_device)
-		goto err;
-
-	mmc_device->priv = host;
-	return mmc_device;
-
-err:
-	free(host);
-	return NULL;
-}
-
 /*
  * mmc_host_init - initialize the mmc controller.
  * Set initial clock and power for mmc slot.
  * Initialize mmc struct and register with mmc framework.
  */
-static int arm_pl180_mmci_host_init(struct mmc *dev)
+int arm_pl180_mmci_init(struct pl180_mmc_host *host)
 {
-	struct mmc_host *host = dev->priv;
+	struct mmc *dev;
 	u32 sdi_u32;
 
-	host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE;
+	dev = malloc(sizeof(struct mmc));
+	if (!dev)
+		return -ENOMEM;
 
-	/* Initially set power-on, full voltage & MMCI read */
-	sdi_u32 = INIT_PWR;
-	writel(sdi_u32, &host->base->power);
+	memset(dev, 0, sizeof(struct mmc));
+	dev->priv = host;
 
-	/* setting clk freq 505KHz */
-	sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN;
-	writel(sdi_u32, &host->base->clock);
+	writel(host->pwr_init, &host->base->power);
+	writel(host->clkdiv_init, &host->base->clock);
 	udelay(CLK_CHANGE_DELAY);
 
 	/* Disable mmc interrupts */
 	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
 	writel(sdi_u32, &host->base->mask0);
-
-	sprintf(dev->name, "MMC");
-	dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1));
+	strncpy(dev->name, host->name, sizeof(dev->name));
 	dev->send_cmd = host_request;
 	dev->set_ios = host_set_ios;
 	dev->init = mmc_host_reset;
 	dev->getcd = NULL;
-	dev->host_caps = 0;
-	dev->voltages = VOLTAGE_WINDOW_MMC;
-	dev->f_min = dev->clock;
-	dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ;
-
-	return 0;
-}
-
-int arm_pl180_mmci_init(void)
-{
-	int error;
-	struct mmc *dev;
-
-	dev = alloc_mmc_struct();
-	if (!dev)
-		return -1;
-
-	error = arm_pl180_mmci_host_init(dev);
-	if (error) {
-		printf("mmci_host_init error - %d\n", error);
-		return -1;
-	}
-
-	dev->b_max = 0;
-
+	dev->host_caps = host->caps;
+	dev->voltages = host->voltages;
+	dev->f_min = host->clock_min;
+	dev->f_max = host->clock_max;
+	dev->b_max = host->b_max;
 	mmc_register(dev);
 	debug("registered mmc interface number is:%d\n", dev->block_dev.dev);
 
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
index 42fbe3e..06709ed 100644
--- a/drivers/mmc/arm_pl180_mmci.h
+++ b/drivers/mmc/arm_pl180_mmci.h
@@ -26,8 +26,6 @@
 #ifndef __ARM_PL180_MMCI_H__
 #define __ARM_PL180_MMCI_H__
 
-int arm_pl180_mmci_init(void);
-
 #define COMMAND_REG_DELAY	300
 #define DATA_REG_DELAY		1000
 #define CLK_CHANGE_DELAY	2000
@@ -59,8 +57,13 @@ int arm_pl180_mmci_init(void);
 #define SDI_CLKCR_WIDBUS_MASK	0x00001800
 #define SDI_CLKCR_WIDBUS_1	0x00000000
 #define SDI_CLKCR_WIDBUS_4	0x00000800
+/* V2 only */
+#define SDI_CLKCR_WIDBUS_8	0x00001000
+#define SDI_CLKCR_NEDGE		0x00002000
+#define SDI_CLKCR_HWFC_EN	0x00004000
 
-#define SDI_CLKCR_CLKDIV_INIT	0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */
+#define SDI_CLKCR_CLKDIV_INIT_V1 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */
+#define SDI_CLKCR_CLKDIV_INIT_V2 0x000000FD
 
 /* SDI command register bits */
 #define SDI_CMD_CMDINDEX_MASK	0x000000FF
@@ -144,6 +147,8 @@ int arm_pl180_mmci_init(void);
 #define SDI_DCTRL_DBOOTMODEEN	0x00002000
 #define SDI_DCTRL_BUSYMODE	0x00004000
 #define SDI_DCTRL_DDR_MODE	0x00008000
+#define SDI_DCTRL_DBLOCKSIZE_V2_MASK   0x7fff0000
+#define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT  16
 
 #define SDI_FIFO_BURST_SIZE	8
 
@@ -180,4 +185,20 @@ struct sdi_registers {
 	u32 pcell_id3;		/* 0xFFC*/
 };
 
+struct pl180_mmc_host {
+	struct sdi_registers *base;
+	char name[32];
+	unsigned int b_max;
+	unsigned int voltages;
+	unsigned int caps;
+	unsigned int clock_in;
+	unsigned int clock_min;
+	unsigned int clock_max;
+	unsigned int clkdiv_init;
+	unsigned int pwr_init;
+	int version2;
+};
+
+int arm_pl180_mmci_init(struct pl180_mmc_host *);
+
 #endif
diff --git a/include/configs/snowball.h b/include/configs/snowball.h
index e9f4fb1..605ba0e 100644
--- a/include/configs/snowball.h
+++ b/include/configs/snowball.h
@@ -246,6 +246,14 @@
 #endif
 
 /*
+ * MMC related configs
+ */
+#define CONFIG_ARM_PL180_MMCI
+#define MMC_BLOCK_SIZE			512
+#define CFG_EMMC_BASE                   0x80114000
+#define CFG_MMC_BASE                    0x80126000
+
+/*
  * FLASH and environment organization
  */
 #define CONFIG_SYS_NO_FLASH
-- 
1.7.5.4



More information about the U-Boot mailing list