aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDinh Nguyen <Dinh.Nguyen@freescale.com>2010-03-19 11:03:03 -0500
committerDinh Nguyen <Dinh.Nguyen@freescale.com>2010-03-19 11:09:46 -0500
commit7a50f35c075243d3785c12e68f229963873a668a (patch)
treedba3f9f46d00aa72cd84392d617d960cb2455688
parentd213f50bb1ab065a62900c3b77c355606cea7515 (diff)
ENGR00121654 MX53 Add eSDHC support
1. Add MX53 eSDHC support. 2. Enable the ACMD12 on all eSDHC platforms. If using CMD12 on MX53 now, the failure to wait for interrupt was observed. Signed-off-by: Lily Zhang <r58066@freescale.com> Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--drivers/mmc/host/mx_sdhci.c44
-rw-r--r--drivers/mmc/host/mx_sdhci.h11
2 files changed, 33 insertions, 22 deletions
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c
index 9ef6432b9c9e..4a6e43c49bc3 100644
--- a/drivers/mmc/host/mx_sdhci.c
+++ b/drivers/mmc/host/mx_sdhci.c
@@ -234,7 +234,7 @@ static void sdhci_init(struct sdhci_host *host)
sdhci_reset(host, SDHCI_RESET_ALL);
- intmask = SDHCI_INT_ADMA_ERROR |
+ intmask = SDHCI_INT_ADMA_ERROR | SDHCI_INT_ACMD12ERR |
SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC |
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
@@ -594,7 +594,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
}
/* We do not handle DMA boundaries, so set it to max (512 KiB) */
- writel((data->blocks << 16) | SDHCI_MAKE_BLKSZ(7, data->blksz),
+ writel((data->blocks << 16) | SDHCI_MAKE_BLKSZ(0, data->blksz),
host->ioaddr + SDHCI_BLOCK_SIZE);
}
@@ -629,19 +629,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
blocks = readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16;
data->bytes_xfered = data->blksz * data->blocks;
- if (data->stop) {
- /*
- * The controller needs a reset of internal state machines
- * upon error conditions.
- */
- if (data->error) {
- sdhci_reset(host, SDHCI_RESET_CMD);
- sdhci_reset(host, SDHCI_RESET_DATA);
- }
-
- sdhci_send_command(host, data->stop);
- } else
- tasklet_schedule(&host->finish_tasklet);
+ tasklet_schedule(&host->finish_tasklet);
}
static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
@@ -679,7 +667,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
udelay(20);
}
- mod_timer(&host->timer, jiffies + 1 * HZ);
+ mod_timer(&host->timer, jiffies + 10 * HZ);
host->cmd = cmd;
@@ -691,7 +679,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (cmd->data != NULL) {
mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DPSEL;
if (cmd->data->blocks > 1)
- mode |= SDHCI_TRNS_MULTI;
+ mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
if (cmd->data->flags & MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
else
@@ -773,7 +761,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
/*This variable holds the value of clock divider, prescaler */
int div = 0, prescaler = 0;
- int clk_rate;
+ int clk_rate = 0;
u32 clk;
unsigned long timeout;
@@ -790,10 +778,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clk_rate = clk_get_rate(host->clk);
clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK;
- writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
+ if (!cpu_is_mx53())
+ writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
if (clock == host->min_clk)
prescaler = 16;
+ else if (cpu_is_mx53())
+ prescaler = 1;
else
prescaler = 0;
while (prescaler <= 0x80) {
@@ -835,7 +826,10 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
}
out:
- host->clock = clock;
+ if (prescaler != 0)
+ host->clock = (clk_rate / (div + 1)) / (prescaler * 2);
+ else
+ host->clock = clk_rate / (div + 1);
}
static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
@@ -1277,6 +1271,16 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
SDHCI_INT_INDEX))
host->cmd->error = -EILSEQ;
+ if (intmask & SDHCI_INT_ACMD12ERR) {
+ int tmp = 0;
+ tmp = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+ if (tmp & (SDHCI_ACMD12_ERR_CE | SDHCI_ACMD12_ERR_IE |
+ SDHCI_ACMD12_ERR_EBE))
+ host->cmd->error = -EILSEQ;
+ else if (tmp & SDHCI_ACMD12_ERR_TOE)
+ host->cmd->error = -ETIMEDOUT;
+ }
+
if (host->cmd->error)
tasklet_schedule(&host->finish_tasklet);
else if (intmask & SDHCI_INT_RESPONSE)
diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h
index 9800f21d13a9..0bd79934952e 100644
--- a/drivers/mmc/host/mx_sdhci.h
+++ b/drivers/mmc/host/mx_sdhci.h
@@ -3,7 +3,7 @@
* Controller Interface driver
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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
@@ -131,7 +131,8 @@
#define SDHCI_INT_ERROR_MASK 0xFFFF8000
#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
- SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \
+ SDHCI_INT_ACMD12ERR)
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
@@ -140,6 +141,12 @@
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)
#define SDHCI_ACMD12_ERR 0x3C
+#define SDHCI_ACMD12_ERR_NE 0x00000001
+#define SDHCI_ACMD12_ERR_TOE 0x00000002
+#define SDHCI_ACMD12_ERR_EBE 0x00000004
+#define SDHCI_ACMD12_ERR_CE 0x00000008
+#define SDHCI_ACMD12_ERR_IE 0x00000010
+#define SDHCI_ACMD12_ERR_CNIBE 0x00000080
/* 3E-3F reserved */