summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorJohn Rigby <john.rigby@linaro.org>2012-07-31 08:59:31 +0000
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>2012-09-01 14:58:20 +0200
commit10ed93dcddeede4e305235367c402fb99e063ef3 (patch)
treea7edb4d8b3aa5d9f4b07a87655ddc84341f2e53a /drivers/mmc
parent75dfe964cbe01ec089e4e3d470a86835776fe248 (diff)
downloadu-boot-imx-10ed93dcddeede4e305235367c402fb99e063ef3.zip
u-boot-imx-10ed93dcddeede4e305235367c402fb99e063ef3.tar.gz
u-boot-imx-10ed93dcddeede4e305235367c402fb99e063ef3.tar.bz2
u8500: Separating mmc config parameters from driver
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@linaro.org> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Signed-off-by: Tom Rini <trini@ti.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/arm_pl180_mmci.c131
-rw-r--r--drivers/mmc/arm_pl180_mmci.h27
2 files changed, 75 insertions, 83 deletions
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index 09d443e..db2c7ab 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -32,14 +32,10 @@
#include "arm_pl180_mmci.h"
#include <malloc.h>
-struct mmc_host {
- struct sdi_registers *base;
-};
-
static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
{
u32 hoststatus, statusmask;
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL;
if ((cmd->resp_type & MMC_RSP_PRESENT))
@@ -53,8 +49,8 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
writel(statusmask, &host->base->status_clear);
if (hoststatus & SDI_STA_CTIMEOUT) {
- printf("CMD%d time out\n", cmd->cmdidx);
- return -ETIMEDOUT;
+ debug("CMD%d time out\n", cmd->cmdidx);
+ return TIMEOUT;
} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
(cmd->flags & MMC_RSP_CRC)) {
printf("CMD%d CRC error\n", cmd->cmdidx);
@@ -80,7 +76,7 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd)
{
int result;
u32 sdi_cmd = 0;
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN);
@@ -112,7 +108,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize)
{
u32 *tempbuff = dest;
u64 xfercount = blkcount * blksize;
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
u32 status, status_err;
debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -168,7 +164,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize)
u32 *tempbuff = src;
int i;
u64 xfercount = blkcount * blksize;
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
u32 status, status_err;
debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize);
@@ -227,14 +223,19 @@ static int do_data_transfer(struct mmc *dev,
struct mmc_data *data)
{
int error = -ETIMEDOUT;
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
u32 blksz = 0;
u32 data_ctrl = 0;
u32 data_len = (u32) (data->blocks * data->blocksize);
- blksz = (ffs(data->blocksize) - 1);
- data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
- data_ctrl |= SDI_DCTRL_DTEN;
+ if (!host->version2) {
+ blksz = (ffs(data->blocksize) - 1);
+ data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK);
+ } else {
+ blksz = data->blocksize;
+ data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT);
+ }
+ data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE;
writel(SDI_DTIMER_DEFAULT, &host->base->datatimer);
writel(data_len, &host->base->datalength);
@@ -257,7 +258,7 @@ static int do_data_transfer(struct mmc *dev,
writel(data_ctrl, &host->base->datactrl);
error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks,
- (u32)data->blocksize);
+ (u32)data->blocksize);
}
return error;
@@ -280,17 +281,16 @@ static int host_request(struct mmc *dev,
/* MMC uses open drain drivers in the enumeration phase */
static int mmc_host_reset(struct mmc *dev)
{
- struct mmc_host *host = dev->priv;
- u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON;
+ struct pl180_mmc_host *host = dev->priv;
- writel(sdi_u32, &host->base->power);
+ writel(host->pwr_init, &host->base->power);
return 0;
}
static void host_set_ios(struct mmc *dev)
{
- struct mmc_host *host = dev->priv;
+ struct pl180_mmc_host *host = dev->priv;
u32 sdi_clkcr;
sdi_clkcr = readl(&host->base->clock);
@@ -298,15 +298,26 @@ static void host_set_ios(struct mmc *dev)
/* Ramp up the clock rate */
if (dev->clock) {
u32 clkdiv = 0;
+ u32 tmp_clock;
- if (dev->clock >= dev->f_max)
+ if (dev->clock >= dev->f_max) {
+ clkdiv = 0;
dev->clock = dev->f_max;
+ } else {
+ clkdiv = (host->clock_in / dev->clock) - 2;
+ }
- clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1;
+ tmp_clock = host->clock_in / (clkdiv + 2);
+ while (tmp_clock > dev->clock) {
+ clkdiv++;
+ tmp_clock = host->clock_in / (clkdiv + 2);
+ }
if (clkdiv > SDI_CLKCR_CLKDIV_MASK)
clkdiv = SDI_CLKCR_CLKDIV_MASK;
+ tmp_clock = host->clock_in / (clkdiv + 2);
+ dev->clock = tmp_clock;
sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK);
sdi_clkcr |= clkdiv;
}
@@ -322,8 +333,11 @@ static void host_set_ios(struct mmc *dev)
case 4:
buswidth |= SDI_CLKCR_WIDBUS_4;
break;
+ case 8:
+ buswidth |= SDI_CLKCR_WIDBUS_8;
+ break;
default:
- printf("Invalid bus width\n");
+ printf("Invalid bus width: %d\n", dev->bus_width);
break;
}
sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK);
@@ -334,83 +348,40 @@ static void host_set_ios(struct mmc *dev)
udelay(CLK_CHANGE_DELAY);
}
-struct mmc *alloc_mmc_struct(void)
-{
- struct mmc_host *host = NULL;
- struct mmc *mmc_device = NULL;
-
- host = malloc(sizeof(struct mmc_host));
- if (!host)
- return NULL;
-
- mmc_device = malloc(sizeof(struct mmc));
- if (!mmc_device)
- goto err;
-
- mmc_device->priv = host;
- return mmc_device;
-
-err:
- free(host);
- return NULL;
-}
-
/*
* mmc_host_init - initialize the mmc controller.
* Set initial clock and power for mmc slot.
* Initialize mmc struct and register with mmc framework.
*/
-static int arm_pl180_mmci_host_init(struct mmc *dev)
+int arm_pl180_mmci_init(struct pl180_mmc_host *host)
{
- struct mmc_host *host = dev->priv;
+ struct mmc *dev;
u32 sdi_u32;
- host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE;
+ dev = malloc(sizeof(struct mmc));
+ if (!dev)
+ return -ENOMEM;
- /* Initially set power-on, full voltage & MMCI read */
- sdi_u32 = INIT_PWR;
- writel(sdi_u32, &host->base->power);
+ memset(dev, 0, sizeof(struct mmc));
+ dev->priv = host;
- /* setting clk freq 505KHz */
- sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN;
- writel(sdi_u32, &host->base->clock);
+ writel(host->pwr_init, &host->base->power);
+ writel(host->clkdiv_init, &host->base->clock);
udelay(CLK_CHANGE_DELAY);
/* Disable mmc interrupts */
sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
writel(sdi_u32, &host->base->mask0);
-
- sprintf(dev->name, "MMC");
- dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1));
+ strncpy(dev->name, host->name, sizeof(dev->name));
dev->send_cmd = host_request;
dev->set_ios = host_set_ios;
dev->init = mmc_host_reset;
dev->getcd = NULL;
- dev->host_caps = 0;
- dev->voltages = VOLTAGE_WINDOW_MMC;
- dev->f_min = dev->clock;
- dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ;
-
- return 0;
-}
-
-int arm_pl180_mmci_init(void)
-{
- int error;
- struct mmc *dev;
-
- dev = alloc_mmc_struct();
- if (!dev)
- return -1;
-
- error = arm_pl180_mmci_host_init(dev);
- if (error) {
- printf("mmci_host_init error - %d\n", error);
- return -1;
- }
-
- dev->b_max = 0;
-
+ dev->host_caps = host->caps;
+ dev->voltages = host->voltages;
+ dev->f_min = host->clock_min;
+ dev->f_max = host->clock_max;
+ dev->b_max = host->b_max;
mmc_register(dev);
debug("registered mmc interface number is:%d\n", dev->block_dev.dev);
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
index 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