diff options
author | Richard Zhu <Hong-Xing.Zhu@freescale.com> | 2011-03-21 01:22:16 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-03-25 10:30:50 -0400 |
commit | 58ac8177cebb890ba980cdace36457e0fe1e62af (patch) | |
tree | 2d5d7946fe1d4f650d79abdef8270809d0bcdbbc | |
parent | e149860d16d96aef1a8eb7dc1d0b9d4313479e61 (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>
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 42 |
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 | ||
30 | struct pltfm_imx_data { | 48 | struct 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) { |