aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c51
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/mmc/host/sdhci.h5
3 files changed, 56 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index cfabc43a4ff2..60de2eeb39b1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -22,6 +22,7 @@
22#include "sdhci-esdhc.h" 22#include "sdhci-esdhc.h"
23 23
24#define VENDOR_V_22 0x12 24#define VENDOR_V_22 0x12
25#define VENDOR_V_23 0x13
25static u32 esdhc_readl(struct sdhci_host *host, int reg) 26static u32 esdhc_readl(struct sdhci_host *host, int reg)
26{ 27{
27 u32 ret; 28 u32 ret;
@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
85 return ret; 86 return ret;
86} 87}
87 88
89static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
90{
91 /*
92 * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
93 * when SYSCTL[RSTD]) is set for some special operations.
94 * No any impact other operation.
95 */
96 if (reg == SDHCI_INT_ENABLE)
97 val |= SDHCI_INT_BLK_GAP;
98 sdhci_be32bs_writel(host, val, reg);
99}
100
88static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) 101static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
89{ 102{
90 if (reg == SDHCI_BLOCK_SIZE) { 103 if (reg == SDHCI_BLOCK_SIZE) {
@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
121 sdhci_be32bs_writeb(host, val, reg); 134 sdhci_be32bs_writeb(host, val, reg);
122} 135}
123 136
137/*
138 * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
139 * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
140 * and Block Gap Event(IRQSTAT[BGE]) are also set.
141 * For Continue, apply soft reset for data(SYSCTL[RSTD]);
142 * and re-issue the entire read transaction from beginning.
143 */
144static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
145{
146 u32 tmp;
147 bool applicable;
148 dma_addr_t dmastart;
149 dma_addr_t dmanow;
150
151 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
152 tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
153
154 applicable = (intmask & SDHCI_INT_DATA_END) &&
155 (intmask & SDHCI_INT_BLK_GAP) &&
156 (tmp == VENDOR_V_23);
157 if (!applicable)
158 return;
159
160 host->data->error = 0;
161 dmastart = sg_dma_address(host->data->sg);
162 dmanow = dmastart + host->data->bytes_xfered;
163 /*
164 * Force update to the next DMA block boundary.
165 */
166 dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
167 SDHCI_DEFAULT_BOUNDARY_SIZE;
168 host->data->bytes_xfered = dmanow - dmastart;
169 sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
170}
171
124static int esdhc_of_enable_dma(struct sdhci_host *host) 172static int esdhc_of_enable_dma(struct sdhci_host *host)
125{ 173{
126 setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); 174 setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
@@ -186,7 +234,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
186 .read_l = esdhc_readl, 234 .read_l = esdhc_readl,
187 .read_w = esdhc_readw, 235 .read_w = esdhc_readw,
188 .read_b = esdhc_readb, 236 .read_b = esdhc_readb,
189 .write_l = sdhci_be32bs_writel, 237 .write_l = esdhc_writel,
190 .write_w = esdhc_writew, 238 .write_w = esdhc_writew,
191 .write_b = esdhc_writeb, 239 .write_b = esdhc_writeb,
192 .set_clock = esdhc_of_set_clock, 240 .set_clock = esdhc_of_set_clock,
@@ -198,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
198 .platform_suspend = esdhc_of_suspend, 246 .platform_suspend = esdhc_of_suspend,
199 .platform_resume = esdhc_of_resume, 247 .platform_resume = esdhc_of_resume,
200#endif 248#endif
249 .adma_workaround = esdhci_of_adma_workaround,
201}; 250};
202 251
203static struct sdhci_pltfm_data sdhci_esdhc_pdata = { 252static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f78c5b1329eb..b2e4b1bab69d 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2282,6 +2282,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
2282 pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); 2282 pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
2283 sdhci_show_adma_error(host); 2283 sdhci_show_adma_error(host);
2284 host->data->error = -EIO; 2284 host->data->error = -EIO;
2285 if (host->ops->adma_workaround)
2286 host->ops->adma_workaround(host, intmask);
2285 } 2287 }
2286 2288
2287 if (host->data->error) 2289 if (host->data->error)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 71a4a7ed46c5..a6d69b7bdea2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -120,6 +120,7 @@
120#define SDHCI_SIGNAL_ENABLE 0x38 120#define SDHCI_SIGNAL_ENABLE 0x38
121#define SDHCI_INT_RESPONSE 0x00000001 121#define SDHCI_INT_RESPONSE 0x00000001
122#define SDHCI_INT_DATA_END 0x00000002 122#define SDHCI_INT_DATA_END 0x00000002
123#define SDHCI_INT_BLK_GAP 0x00000004
123#define SDHCI_INT_DMA_END 0x00000008 124#define SDHCI_INT_DMA_END 0x00000008
124#define SDHCI_INT_SPACE_AVAIL 0x00000010 125#define SDHCI_INT_SPACE_AVAIL 0x00000010
125#define SDHCI_INT_DATA_AVAIL 0x00000020 126#define SDHCI_INT_DATA_AVAIL 0x00000020
@@ -146,7 +147,8 @@
146#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ 147#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
147 SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ 148 SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
148 SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ 149 SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
149 SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) 150 SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
151 SDHCI_INT_BLK_GAP)
150#define SDHCI_INT_ALL_MASK ((unsigned int)-1) 152#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
151 153
152#define SDHCI_ACMD12_ERR 0x3C 154#define SDHCI_ACMD12_ERR 0x3C
@@ -278,6 +280,7 @@ struct sdhci_ops {
278 void (*hw_reset)(struct sdhci_host *host); 280 void (*hw_reset)(struct sdhci_host *host);
279 void (*platform_suspend)(struct sdhci_host *host); 281 void (*platform_suspend)(struct sdhci_host *host);
280 void (*platform_resume)(struct sdhci_host *host); 282 void (*platform_resume)(struct sdhci_host *host);
283 void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
281 void (*platform_init)(struct sdhci_host *host); 284 void (*platform_init)(struct sdhci_host *host);
282}; 285};
283 286