aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRichard Zhu <Hong-Xing.Zhu@freescale.com>2011-03-21 01:22:16 -0400
committerChris Ball <cjb@laptop.org>2011-03-25 10:30:50 -0400
commit58ac8177cebb890ba980cdace36457e0fe1e62af (patch)
tree2d5d7946fe1d4f650d79abdef8270809d0bcdbbc /drivers
parente149860d16d96aef1a8eb7dc1d0b9d4313479e61 (diff)
mmc: sdhci-esdhc: enable esdhc on imx53
Fix the NO INT in the Multi-BLK IO in SD/MMC, and Multi-BLK read in SDIO on imx53. The CMDTYPE of the CMD register (offset 0xE) should be set to "11" when the STOP CMD12 is issued on imx53 to abort one open ended multi-blk IO. Otherwise the TC INT wouldn't be generated. In exact block transfer, the controller doesn't complete the operations automatically as required at the end of the transfer and remains on hold if the abort command is not sent on imx53. As a result, the TC flag is not asserted and SW receives timeout exception. Set bit1 of Vendor Spec register to fix it. Signed-off-by: Richard Zhu <Hong-Xing.Zhu@freescale.com> Signed-off-by: Richard Zhao <richard.zhao@freescale.com> Reviewed-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 67a2da961bb5..a19967d0bfc4 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -19,13 +19,31 @@
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/mmc/host.h> 20#include <linux/mmc/host.h>
21#include <linux/mmc/sdhci-pltfm.h> 21#include <linux/mmc/sdhci-pltfm.h>
22#include <linux/mmc/mmc.h>
23#include <linux/mmc/sdio.h>
22#include <mach/hardware.h> 24#include <mach/hardware.h>
23#include <mach/esdhc.h> 25#include <mach/esdhc.h>
24#include "sdhci.h" 26#include "sdhci.h"
25#include "sdhci-pltfm.h" 27#include "sdhci-pltfm.h"
26#include "sdhci-esdhc.h" 28#include "sdhci-esdhc.h"
27 29
30/* VENDOR SPEC register */
31#define SDHCI_VENDOR_SPEC 0xC0
32#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
33
28#define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) 34#define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0)
35/*
36 * The CMDTYPE of the CMD register (offset 0xE) should be set to
37 * "11" when the STOP CMD12 is issued on imx53 to abort one
38 * open ended multi-blk IO. Otherwise the TC INT wouldn't
39 * be generated.
40 * In exact block transfer, the controller doesn't complete the
41 * operations automatically as required at the end of the
42 * transfer and remains on hold if the abort command is not sent.
43 * As a result, the TC flag is not asserted and SW received timeout
44 * exeception. Bit1 of Vendor Spec registor is used to fix it.
45 */
46#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
29 47
30struct pltfm_imx_data { 48struct pltfm_imx_data {
31 int flags; 49 int flags;
@@ -78,6 +96,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
78 */ 96 */
79 val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); 97 val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
80 98
99 if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
100 && (reg == SDHCI_INT_STATUS)
101 && (val & SDHCI_INT_DATA_END))) {
102 u32 v;
103 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
104 v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
105 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
106 }
107
81 writel(val, host->ioaddr + reg); 108 writel(val, host->ioaddr + reg);
82} 109}
83 110
@@ -100,9 +127,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
100 * Postpone this write, we must do it together with a 127 * Postpone this write, we must do it together with a
101 * command write that is down below. 128 * command write that is down below.
102 */ 129 */
130 if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
131 && (host->cmd->opcode == SD_IO_RW_EXTENDED)
132 && (host->cmd->data->blocks > 1)
133 && (host->cmd->data->flags & MMC_DATA_READ)) {
134 u32 v;
135 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
136 v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
137 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
138 }
103 imx_data->scratchpad = val; 139 imx_data->scratchpad = val;
104 return; 140 return;
105 case SDHCI_COMMAND: 141 case SDHCI_COMMAND:
142 if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
143 && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
144 val |= SDHCI_CMD_ABORTCMD;
106 writel(val << 16 | imx_data->scratchpad, 145 writel(val << 16 | imx_data->scratchpad,
107 host->ioaddr + SDHCI_TRANSFER_MODE); 146 host->ioaddr + SDHCI_TRANSFER_MODE);
108 return; 147 return;
@@ -215,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
215 sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; 254 sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
216 } 255 }
217 256
257 if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
258 imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
259
218 if (boarddata) { 260 if (boarddata) {
219 err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); 261 err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
220 if (err) { 262 if (err) {