diff options
Diffstat (limited to 'drivers/mmc/host/au1xmmc.c')
-rw-r--r-- | drivers/mmc/host/au1xmmc.c | 792 |
1 files changed, 469 insertions, 323 deletions
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index cc5f7bc546af..3f15eb204895 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c | |||
@@ -21,7 +21,7 @@ | |||
21 | * published by the Free Software Foundation. | 21 | * published by the Free Software Foundation. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* Why is a timer used to detect insert events? | 24 | /* Why don't we use the SD controllers' carddetect feature? |
25 | * | 25 | * |
26 | * From the AU1100 MMC application guide: | 26 | * From the AU1100 MMC application guide: |
27 | * If the Au1100-based design is intended to support both MultiMediaCards | 27 | * If the Au1100-based design is intended to support both MultiMediaCards |
@@ -30,8 +30,6 @@ | |||
30 | * In doing so, a MMC card never enters SPI-mode communications, | 30 | * In doing so, a MMC card never enters SPI-mode communications, |
31 | * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective | 31 | * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective |
32 | * (the low to high transition will not occur). | 32 | * (the low to high transition will not occur). |
33 | * | ||
34 | * So we use the timer to check the status manually. | ||
35 | */ | 33 | */ |
36 | 34 | ||
37 | #include <linux/module.h> | 35 | #include <linux/module.h> |
@@ -41,51 +39,110 @@ | |||
41 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
42 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
43 | #include <linux/scatterlist.h> | 41 | #include <linux/scatterlist.h> |
44 | 42 | #include <linux/leds.h> | |
45 | #include <linux/mmc/host.h> | 43 | #include <linux/mmc/host.h> |
44 | |||
46 | #include <asm/io.h> | 45 | #include <asm/io.h> |
47 | #include <asm/mach-au1x00/au1000.h> | 46 | #include <asm/mach-au1x00/au1000.h> |
48 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | 47 | #include <asm/mach-au1x00/au1xxx_dbdma.h> |
49 | #include <asm/mach-au1x00/au1100_mmc.h> | 48 | #include <asm/mach-au1x00/au1100_mmc.h> |
50 | 49 | ||
51 | #include <au1xxx.h> | ||
52 | #include "au1xmmc.h" | ||
53 | |||
54 | #define DRIVER_NAME "au1xxx-mmc" | 50 | #define DRIVER_NAME "au1xxx-mmc" |
55 | 51 | ||
56 | /* Set this to enable special debugging macros */ | 52 | /* Set this to enable special debugging macros */ |
53 | /* #define DEBUG */ | ||
57 | 54 | ||
58 | #ifdef DEBUG | 55 | #ifdef DEBUG |
59 | #define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args) | 56 | #define DBG(fmt, idx, args...) \ |
57 | printk(KERN_DEBUG "au1xmmc(%d): DEBUG: " fmt, idx, ##args) | ||
60 | #else | 58 | #else |
61 | #define DBG(fmt, idx, args...) | 59 | #define DBG(fmt, idx, args...) do {} while (0) |
62 | #endif | 60 | #endif |
63 | 61 | ||
64 | const struct { | 62 | /* Hardware definitions */ |
63 | #define AU1XMMC_DESCRIPTOR_COUNT 1 | ||
64 | #define AU1XMMC_DESCRIPTOR_SIZE 2048 | ||
65 | |||
66 | #define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \ | ||
67 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \ | ||
68 | MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36) | ||
69 | |||
70 | /* This gives us a hard value for the stop command that we can write directly | ||
71 | * to the command register. | ||
72 | */ | ||
73 | #define STOP_CMD \ | ||
74 | (SD_CMD_RT_1B | SD_CMD_CT_7 | (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO) | ||
75 | |||
76 | /* This is the set of interrupts that we configure by default. */ | ||
77 | #define AU1XMMC_INTERRUPTS \ | ||
78 | (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_RAT | \ | ||
79 | SD_CONFIG_CR | SD_CONFIG_I) | ||
80 | |||
81 | /* The poll event (looking for insert/remove events runs twice a second. */ | ||
82 | #define AU1XMMC_DETECT_TIMEOUT (HZ/2) | ||
83 | |||
84 | struct au1xmmc_host { | ||
85 | struct mmc_host *mmc; | ||
86 | struct mmc_request *mrq; | ||
87 | |||
88 | u32 flags; | ||
65 | u32 iobase; | 89 | u32 iobase; |
66 | u32 tx_devid, rx_devid; | 90 | u32 clock; |
67 | u16 bcsrpwr; | 91 | u32 bus_width; |
68 | u16 bcsrstatus; | 92 | u32 power_mode; |
69 | u16 wpstatus; | ||
70 | } au1xmmc_card_table[] = { | ||
71 | { SD0_BASE, DSCR_CMD0_SDMS_TX0, DSCR_CMD0_SDMS_RX0, | ||
72 | BCSR_BOARD_SD0PWR, BCSR_INT_SD0INSERT, BCSR_STATUS_SD0WP }, | ||
73 | #ifndef CONFIG_MIPS_DB1200 | ||
74 | { SD1_BASE, DSCR_CMD0_SDMS_TX1, DSCR_CMD0_SDMS_RX1, | ||
75 | BCSR_BOARD_DS1PWR, BCSR_INT_SD1INSERT, BCSR_STATUS_SD1WP } | ||
76 | #endif | ||
77 | }; | ||
78 | 93 | ||
79 | #define AU1XMMC_CONTROLLER_COUNT (ARRAY_SIZE(au1xmmc_card_table)) | 94 | int status; |
80 | 95 | ||
81 | /* This array stores pointers for the hosts (used by the IRQ handler) */ | 96 | struct { |
82 | struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT]; | 97 | int len; |
83 | static int dma = 1; | 98 | int dir; |
99 | } dma; | ||
84 | 100 | ||
85 | #ifdef MODULE | 101 | struct { |
86 | module_param(dma, bool, 0); | 102 | int index; |
87 | MODULE_PARM_DESC(dma, "Use DMA engine for data transfers (0 = disabled)"); | 103 | int offset; |
88 | #endif | 104 | int len; |
105 | } pio; | ||
106 | |||
107 | u32 tx_chan; | ||
108 | u32 rx_chan; | ||
109 | |||
110 | int irq; | ||
111 | |||
112 | struct tasklet_struct finish_task; | ||
113 | struct tasklet_struct data_task; | ||
114 | struct au1xmmc_platform_data *platdata; | ||
115 | struct platform_device *pdev; | ||
116 | struct resource *ioarea; | ||
117 | }; | ||
118 | |||
119 | /* Status flags used by the host structure */ | ||
120 | #define HOST_F_XMIT 0x0001 | ||
121 | #define HOST_F_RECV 0x0002 | ||
122 | #define HOST_F_DMA 0x0010 | ||
123 | #define HOST_F_ACTIVE 0x0100 | ||
124 | #define HOST_F_STOP 0x1000 | ||
125 | |||
126 | #define HOST_S_IDLE 0x0001 | ||
127 | #define HOST_S_CMD 0x0002 | ||
128 | #define HOST_S_DATA 0x0003 | ||
129 | #define HOST_S_STOP 0x0004 | ||
130 | |||
131 | /* Easy access macros */ | ||
132 | #define HOST_STATUS(h) ((h)->iobase + SD_STATUS) | ||
133 | #define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG) | ||
134 | #define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE) | ||
135 | #define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT) | ||
136 | #define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT) | ||
137 | #define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG) | ||
138 | #define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE) | ||
139 | #define HOST_CMD(h) ((h)->iobase + SD_CMD) | ||
140 | #define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2) | ||
141 | #define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT) | ||
142 | #define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG) | ||
143 | |||
144 | #define DMA_CHANNEL(h) \ | ||
145 | (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan) | ||
89 | 146 | ||
90 | static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) | 147 | static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask) |
91 | { | 148 | { |
@@ -119,14 +176,13 @@ static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask) | |||
119 | 176 | ||
120 | static inline void SEND_STOP(struct au1xmmc_host *host) | 177 | static inline void SEND_STOP(struct au1xmmc_host *host) |
121 | { | 178 | { |
122 | 179 | u32 config2; | |
123 | /* We know the value of CONFIG2, so avoid a read we don't need */ | ||
124 | u32 mask = SD_CONFIG2_EN; | ||
125 | 180 | ||
126 | WARN_ON(host->status != HOST_S_DATA); | 181 | WARN_ON(host->status != HOST_S_DATA); |
127 | host->status = HOST_S_STOP; | 182 | host->status = HOST_S_STOP; |
128 | 183 | ||
129 | au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host)); | 184 | config2 = au_readl(HOST_CONFIG2(host)); |
185 | au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host)); | ||
130 | au_sync(); | 186 | au_sync(); |
131 | 187 | ||
132 | /* Send the stop commmand */ | 188 | /* Send the stop commmand */ |
@@ -135,35 +191,36 @@ static inline void SEND_STOP(struct au1xmmc_host *host) | |||
135 | 191 | ||
136 | static void au1xmmc_set_power(struct au1xmmc_host *host, int state) | 192 | static void au1xmmc_set_power(struct au1xmmc_host *host, int state) |
137 | { | 193 | { |
138 | 194 | if (host->platdata && host->platdata->set_power) | |
139 | u32 val = au1xmmc_card_table[host->id].bcsrpwr; | 195 | host->platdata->set_power(host->mmc, state); |
140 | |||
141 | bcsr->board &= ~val; | ||
142 | if (state) bcsr->board |= val; | ||
143 | |||
144 | au_sync_delay(1); | ||
145 | } | 196 | } |
146 | 197 | ||
147 | static inline int au1xmmc_card_inserted(struct au1xmmc_host *host) | 198 | static int au1xmmc_card_inserted(struct mmc_host *mmc) |
148 | { | 199 | { |
149 | return (bcsr->sig_status & au1xmmc_card_table[host->id].bcsrstatus) | 200 | struct au1xmmc_host *host = mmc_priv(mmc); |
150 | ? 1 : 0; | 201 | |
202 | if (host->platdata && host->platdata->card_inserted) | ||
203 | return !!host->platdata->card_inserted(host->mmc); | ||
204 | |||
205 | return -ENOSYS; | ||
151 | } | 206 | } |
152 | 207 | ||
153 | static int au1xmmc_card_readonly(struct mmc_host *mmc) | 208 | static int au1xmmc_card_readonly(struct mmc_host *mmc) |
154 | { | 209 | { |
155 | struct au1xmmc_host *host = mmc_priv(mmc); | 210 | struct au1xmmc_host *host = mmc_priv(mmc); |
156 | return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) | 211 | |
157 | ? 1 : 0; | 212 | if (host->platdata && host->platdata->card_readonly) |
213 | return !!host->platdata->card_readonly(mmc); | ||
214 | |||
215 | return -ENOSYS; | ||
158 | } | 216 | } |
159 | 217 | ||
160 | static void au1xmmc_finish_request(struct au1xmmc_host *host) | 218 | static void au1xmmc_finish_request(struct au1xmmc_host *host) |
161 | { | 219 | { |
162 | |||
163 | struct mmc_request *mrq = host->mrq; | 220 | struct mmc_request *mrq = host->mrq; |
164 | 221 | ||
165 | host->mrq = NULL; | 222 | host->mrq = NULL; |
166 | host->flags &= HOST_F_ACTIVE; | 223 | host->flags &= HOST_F_ACTIVE | HOST_F_DMA; |
167 | 224 | ||
168 | host->dma.len = 0; | 225 | host->dma.len = 0; |
169 | host->dma.dir = 0; | 226 | host->dma.dir = 0; |
@@ -174,8 +231,6 @@ static void au1xmmc_finish_request(struct au1xmmc_host *host) | |||
174 | 231 | ||
175 | host->status = HOST_S_IDLE; | 232 | host->status = HOST_S_IDLE; |
176 | 233 | ||
177 | bcsr->disk_leds |= (1 << 8); | ||
178 | |||
179 | mmc_request_done(host->mmc, mrq); | 234 | mmc_request_done(host->mmc, mrq); |
180 | } | 235 | } |
181 | 236 | ||
@@ -235,18 +290,14 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, | |||
235 | au_sync(); | 290 | au_sync(); |
236 | 291 | ||
237 | /* Wait for the command to go on the line */ | 292 | /* Wait for the command to go on the line */ |
238 | 293 | while (au_readl(HOST_CMD(host)) & SD_CMD_GO) | |
239 | while(1) { | 294 | /* nop */; |
240 | if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO)) | ||
241 | break; | ||
242 | } | ||
243 | 295 | ||
244 | /* Wait for the command to come back */ | 296 | /* Wait for the command to come back */ |
245 | |||
246 | if (wait) { | 297 | if (wait) { |
247 | u32 status = au_readl(HOST_STATUS(host)); | 298 | u32 status = au_readl(HOST_STATUS(host)); |
248 | 299 | ||
249 | while(!(status & SD_STATUS_CR)) | 300 | while (!(status & SD_STATUS_CR)) |
250 | status = au_readl(HOST_STATUS(host)); | 301 | status = au_readl(HOST_STATUS(host)); |
251 | 302 | ||
252 | /* Clear the CR status */ | 303 | /* Clear the CR status */ |
@@ -260,12 +311,11 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, | |||
260 | 311 | ||
261 | static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) | 312 | static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) |
262 | { | 313 | { |
263 | |||
264 | struct mmc_request *mrq = host->mrq; | 314 | struct mmc_request *mrq = host->mrq; |
265 | struct mmc_data *data; | 315 | struct mmc_data *data; |
266 | u32 crc; | 316 | u32 crc; |
267 | 317 | ||
268 | WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP); | 318 | WARN_ON((host->status != HOST_S_DATA) && (host->status != HOST_S_STOP)); |
269 | 319 | ||
270 | if (host->mrq == NULL) | 320 | if (host->mrq == NULL) |
271 | return; | 321 | return; |
@@ -276,15 +326,13 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) | |||
276 | status = au_readl(HOST_STATUS(host)); | 326 | status = au_readl(HOST_STATUS(host)); |
277 | 327 | ||
278 | /* The transaction is really over when the SD_STATUS_DB bit is clear */ | 328 | /* The transaction is really over when the SD_STATUS_DB bit is clear */ |
279 | 329 | while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) | |
280 | while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB)) | ||
281 | status = au_readl(HOST_STATUS(host)); | 330 | status = au_readl(HOST_STATUS(host)); |
282 | 331 | ||
283 | data->error = 0; | 332 | data->error = 0; |
284 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); | 333 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); |
285 | 334 | ||
286 | /* Process any errors */ | 335 | /* Process any errors */ |
287 | |||
288 | crc = (status & (SD_STATUS_WC | SD_STATUS_RC)); | 336 | crc = (status & (SD_STATUS_WC | SD_STATUS_RC)); |
289 | if (host->flags & HOST_F_XMIT) | 337 | if (host->flags & HOST_F_XMIT) |
290 | crc |= ((status & 0x07) == 0x02) ? 0 : 1; | 338 | crc |= ((status & 0x07) == 0x02) ? 0 : 1; |
@@ -299,16 +347,16 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) | |||
299 | 347 | ||
300 | if (!data->error) { | 348 | if (!data->error) { |
301 | if (host->flags & HOST_F_DMA) { | 349 | if (host->flags & HOST_F_DMA) { |
350 | #ifdef CONFIG_SOC_AU1200 /* DBDMA */ | ||
302 | u32 chan = DMA_CHANNEL(host); | 351 | u32 chan = DMA_CHANNEL(host); |
303 | 352 | ||
304 | chan_tab_t *c = *((chan_tab_t **) chan); | 353 | chan_tab_t *c = *((chan_tab_t **)chan); |
305 | au1x_dma_chan_t *cp = c->chan_ptr; | 354 | au1x_dma_chan_t *cp = c->chan_ptr; |
306 | data->bytes_xfered = cp->ddma_bytecnt; | 355 | data->bytes_xfered = cp->ddma_bytecnt; |
307 | } | 356 | #endif |
308 | else | 357 | } else |
309 | data->bytes_xfered = | 358 | data->bytes_xfered = |
310 | (data->blocks * data->blksz) - | 359 | (data->blocks * data->blksz) - host->pio.len; |
311 | host->pio.len; | ||
312 | } | 360 | } |
313 | 361 | ||
314 | au1xmmc_finish_request(host); | 362 | au1xmmc_finish_request(host); |
@@ -316,7 +364,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) | |||
316 | 364 | ||
317 | static void au1xmmc_tasklet_data(unsigned long param) | 365 | static void au1xmmc_tasklet_data(unsigned long param) |
318 | { | 366 | { |
319 | struct au1xmmc_host *host = (struct au1xmmc_host *) param; | 367 | struct au1xmmc_host *host = (struct au1xmmc_host *)param; |
320 | 368 | ||
321 | u32 status = au_readl(HOST_STATUS(host)); | 369 | u32 status = au_readl(HOST_STATUS(host)); |
322 | au1xmmc_data_complete(host, status); | 370 | au1xmmc_data_complete(host, status); |
@@ -326,11 +374,10 @@ static void au1xmmc_tasklet_data(unsigned long param) | |||
326 | 374 | ||
327 | static void au1xmmc_send_pio(struct au1xmmc_host *host) | 375 | static void au1xmmc_send_pio(struct au1xmmc_host *host) |
328 | { | 376 | { |
329 | 377 | struct mmc_data *data; | |
330 | struct mmc_data *data = 0; | 378 | int sg_len, max, count; |
331 | int sg_len, max, count = 0; | 379 | unsigned char *sg_ptr, val; |
332 | unsigned char *sg_ptr; | 380 | u32 status; |
333 | u32 status = 0; | ||
334 | struct scatterlist *sg; | 381 | struct scatterlist *sg; |
335 | 382 | ||
336 | data = host->mrq->data; | 383 | data = host->mrq->data; |
@@ -345,14 +392,12 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) | |||
345 | /* This is the space left inside the buffer */ | 392 | /* This is the space left inside the buffer */ |
346 | sg_len = data->sg[host->pio.index].length - host->pio.offset; | 393 | sg_len = data->sg[host->pio.index].length - host->pio.offset; |
347 | 394 | ||
348 | /* Check to if we need less then the size of the sg_buffer */ | 395 | /* Check if we need less than the size of the sg_buffer */ |
349 | |||
350 | max = (sg_len > host->pio.len) ? host->pio.len : sg_len; | 396 | max = (sg_len > host->pio.len) ? host->pio.len : sg_len; |
351 | if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER; | 397 | if (max > AU1XMMC_MAX_TRANSFER) |
352 | 398 | max = AU1XMMC_MAX_TRANSFER; | |
353 | for(count = 0; count < max; count++ ) { | ||
354 | unsigned char val; | ||
355 | 399 | ||
400 | for (count = 0; count < max; count++) { | ||
356 | status = au_readl(HOST_STATUS(host)); | 401 | status = au_readl(HOST_STATUS(host)); |
357 | 402 | ||
358 | if (!(status & SD_STATUS_TH)) | 403 | if (!(status & SD_STATUS_TH)) |
@@ -360,7 +405,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) | |||
360 | 405 | ||
361 | val = *sg_ptr++; | 406 | val = *sg_ptr++; |
362 | 407 | ||
363 | au_writel((unsigned long) val, HOST_TXPORT(host)); | 408 | au_writel((unsigned long)val, HOST_TXPORT(host)); |
364 | au_sync(); | 409 | au_sync(); |
365 | } | 410 | } |
366 | 411 | ||
@@ -384,11 +429,10 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host) | |||
384 | 429 | ||
385 | static void au1xmmc_receive_pio(struct au1xmmc_host *host) | 430 | static void au1xmmc_receive_pio(struct au1xmmc_host *host) |
386 | { | 431 | { |
387 | 432 | struct mmc_data *data; | |
388 | struct mmc_data *data = 0; | 433 | int max, count, sg_len = 0; |
389 | int sg_len = 0, max = 0, count = 0; | 434 | unsigned char *sg_ptr = NULL; |
390 | unsigned char *sg_ptr = 0; | 435 | u32 status, val; |
391 | u32 status = 0; | ||
392 | struct scatterlist *sg; | 436 | struct scatterlist *sg; |
393 | 437 | ||
394 | data = host->mrq->data; | 438 | data = host->mrq->data; |
@@ -405,33 +449,33 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) | |||
405 | /* This is the space left inside the buffer */ | 449 | /* This is the space left inside the buffer */ |
406 | sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; | 450 | sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; |
407 | 451 | ||
408 | /* Check to if we need less then the size of the sg_buffer */ | 452 | /* Check if we need less than the size of the sg_buffer */ |
409 | if (sg_len < max) max = sg_len; | 453 | if (sg_len < max) |
454 | max = sg_len; | ||
410 | } | 455 | } |
411 | 456 | ||
412 | if (max > AU1XMMC_MAX_TRANSFER) | 457 | if (max > AU1XMMC_MAX_TRANSFER) |
413 | max = AU1XMMC_MAX_TRANSFER; | 458 | max = AU1XMMC_MAX_TRANSFER; |
414 | 459 | ||
415 | for(count = 0; count < max; count++ ) { | 460 | for (count = 0; count < max; count++) { |
416 | u32 val; | ||
417 | status = au_readl(HOST_STATUS(host)); | 461 | status = au_readl(HOST_STATUS(host)); |
418 | 462 | ||
419 | if (!(status & SD_STATUS_NE)) | 463 | if (!(status & SD_STATUS_NE)) |
420 | break; | 464 | break; |
421 | 465 | ||
422 | if (status & SD_STATUS_RC) { | 466 | if (status & SD_STATUS_RC) { |
423 | DBG("RX CRC Error [%d + %d].\n", host->id, | 467 | DBG("RX CRC Error [%d + %d].\n", host->pdev->id, |
424 | host->pio.len, count); | 468 | host->pio.len, count); |
425 | break; | 469 | break; |
426 | } | 470 | } |
427 | 471 | ||
428 | if (status & SD_STATUS_RO) { | 472 | if (status & SD_STATUS_RO) { |
429 | DBG("RX Overrun [%d + %d]\n", host->id, | 473 | DBG("RX Overrun [%d + %d]\n", host->pdev->id, |
430 | host->pio.len, count); | 474 | host->pio.len, count); |
431 | break; | 475 | break; |
432 | } | 476 | } |
433 | else if (status & SD_STATUS_RU) { | 477 | else if (status & SD_STATUS_RU) { |
434 | DBG("RX Underrun [%d + %d]\n", host->id, | 478 | DBG("RX Underrun [%d + %d]\n", host->pdev->id, |
435 | host->pio.len, count); | 479 | host->pio.len, count); |
436 | break; | 480 | break; |
437 | } | 481 | } |
@@ -439,7 +483,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) | |||
439 | val = au_readl(HOST_RXPORT(host)); | 483 | val = au_readl(HOST_RXPORT(host)); |
440 | 484 | ||
441 | if (sg_ptr) | 485 | if (sg_ptr) |
442 | *sg_ptr++ = (unsigned char) (val & 0xFF); | 486 | *sg_ptr++ = (unsigned char)(val & 0xFF); |
443 | } | 487 | } |
444 | 488 | ||
445 | host->pio.len -= count; | 489 | host->pio.len -= count; |
@@ -451,7 +495,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) | |||
451 | } | 495 | } |
452 | 496 | ||
453 | if (host->pio.len == 0) { | 497 | if (host->pio.len == 0) { |
454 | //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); | 498 | /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */ |
455 | IRQ_OFF(host, SD_CONFIG_NE); | 499 | IRQ_OFF(host, SD_CONFIG_NE); |
456 | 500 | ||
457 | if (host->flags & HOST_F_STOP) | 501 | if (host->flags & HOST_F_STOP) |
@@ -461,17 +505,15 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) | |||
461 | } | 505 | } |
462 | } | 506 | } |
463 | 507 | ||
464 | /* static void au1xmmc_cmd_complete | 508 | /* This is called when a command has been completed - grab the response |
465 | This is called when a command has been completed - grab the response | 509 | * and check for errors. Then start the data transfer if it is indicated. |
466 | and check for errors. Then start the data transfer if it is indicated. | 510 | */ |
467 | */ | ||
468 | |||
469 | static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | 511 | static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) |
470 | { | 512 | { |
471 | |||
472 | struct mmc_request *mrq = host->mrq; | 513 | struct mmc_request *mrq = host->mrq; |
473 | struct mmc_command *cmd; | 514 | struct mmc_command *cmd; |
474 | int trans; | 515 | u32 r[4]; |
516 | int i, trans; | ||
475 | 517 | ||
476 | if (!host->mrq) | 518 | if (!host->mrq) |
477 | return; | 519 | return; |
@@ -481,9 +523,6 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | |||
481 | 523 | ||
482 | if (cmd->flags & MMC_RSP_PRESENT) { | 524 | if (cmd->flags & MMC_RSP_PRESENT) { |
483 | if (cmd->flags & MMC_RSP_136) { | 525 | if (cmd->flags & MMC_RSP_136) { |
484 | u32 r[4]; | ||
485 | int i; | ||
486 | |||
487 | r[0] = au_readl(host->iobase + SD_RESP3); | 526 | r[0] = au_readl(host->iobase + SD_RESP3); |
488 | r[1] = au_readl(host->iobase + SD_RESP2); | 527 | r[1] = au_readl(host->iobase + SD_RESP2); |
489 | r[2] = au_readl(host->iobase + SD_RESP1); | 528 | r[2] = au_readl(host->iobase + SD_RESP1); |
@@ -491,10 +530,9 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | |||
491 | 530 | ||
492 | /* The CRC is omitted from the response, so really | 531 | /* The CRC is omitted from the response, so really |
493 | * we only got 120 bytes, but the engine expects | 532 | * we only got 120 bytes, but the engine expects |
494 | * 128 bits, so we have to shift things up | 533 | * 128 bits, so we have to shift things up. |
495 | */ | 534 | */ |
496 | 535 | for (i = 0; i < 4; i++) { | |
497 | for(i = 0; i < 4; i++) { | ||
498 | cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; | 536 | cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8; |
499 | if (i != 3) | 537 | if (i != 3) |
500 | cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; | 538 | cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; |
@@ -505,22 +543,20 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | |||
505 | * our response omits the CRC, our data ends up | 543 | * our response omits the CRC, our data ends up |
506 | * being shifted 8 bits to the right. In this case, | 544 | * being shifted 8 bits to the right. In this case, |
507 | * that means that the OSR data starts at bit 31, | 545 | * that means that the OSR data starts at bit 31, |
508 | * so we can just read RESP0 and return that | 546 | * so we can just read RESP0 and return that. |
509 | */ | 547 | */ |
510 | cmd->resp[0] = au_readl(host->iobase + SD_RESP0); | 548 | cmd->resp[0] = au_readl(host->iobase + SD_RESP0); |
511 | } | 549 | } |
512 | } | 550 | } |
513 | 551 | ||
514 | /* Figure out errors */ | 552 | /* Figure out errors */ |
515 | |||
516 | if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) | 553 | if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC)) |
517 | cmd->error = -EILSEQ; | 554 | cmd->error = -EILSEQ; |
518 | 555 | ||
519 | trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); | 556 | trans = host->flags & (HOST_F_XMIT | HOST_F_RECV); |
520 | 557 | ||
521 | if (!trans || cmd->error) { | 558 | if (!trans || cmd->error) { |
522 | 559 | IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); | |
523 | IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF); | ||
524 | tasklet_schedule(&host->finish_task); | 560 | tasklet_schedule(&host->finish_task); |
525 | return; | 561 | return; |
526 | } | 562 | } |
@@ -528,6 +564,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | |||
528 | host->status = HOST_S_DATA; | 564 | host->status = HOST_S_DATA; |
529 | 565 | ||
530 | if (host->flags & HOST_F_DMA) { | 566 | if (host->flags & HOST_F_DMA) { |
567 | #ifdef CONFIG_SOC_AU1200 /* DBDMA */ | ||
531 | u32 channel = DMA_CHANNEL(host); | 568 | u32 channel = DMA_CHANNEL(host); |
532 | 569 | ||
533 | /* Start the DMA as soon as the buffer gets something in it */ | 570 | /* Start the DMA as soon as the buffer gets something in it */ |
@@ -540,23 +577,21 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) | |||
540 | } | 577 | } |
541 | 578 | ||
542 | au1xxx_dbdma_start(channel); | 579 | au1xxx_dbdma_start(channel); |
580 | #endif | ||
543 | } | 581 | } |
544 | } | 582 | } |
545 | 583 | ||
546 | static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) | 584 | static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) |
547 | { | 585 | { |
548 | |||
549 | unsigned int pbus = get_au1x00_speed(); | 586 | unsigned int pbus = get_au1x00_speed(); |
550 | unsigned int divisor; | 587 | unsigned int divisor; |
551 | u32 config; | 588 | u32 config; |
552 | 589 | ||
553 | /* From databook: | 590 | /* From databook: |
554 | divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1 | 591 | * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1 |
555 | */ | 592 | */ |
556 | |||
557 | pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2); | 593 | pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2); |
558 | pbus /= 2; | 594 | pbus /= 2; |
559 | |||
560 | divisor = ((pbus / rate) / 2) - 1; | 595 | divisor = ((pbus / rate) / 2) - 1; |
561 | 596 | ||
562 | config = au_readl(HOST_CONFIG(host)); | 597 | config = au_readl(HOST_CONFIG(host)); |
@@ -568,15 +603,11 @@ static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate) | |||
568 | au_sync(); | 603 | au_sync(); |
569 | } | 604 | } |
570 | 605 | ||
571 | static int | 606 | static int au1xmmc_prepare_data(struct au1xmmc_host *host, |
572 | au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | 607 | struct mmc_data *data) |
573 | { | 608 | { |
574 | |||
575 | int datalen = data->blocks * data->blksz; | 609 | int datalen = data->blocks * data->blksz; |
576 | 610 | ||
577 | if (dma != 0) | ||
578 | host->flags |= HOST_F_DMA; | ||
579 | |||
580 | if (data->flags & MMC_DATA_READ) | 611 | if (data->flags & MMC_DATA_READ) |
581 | host->flags |= HOST_F_RECV; | 612 | host->flags |= HOST_F_RECV; |
582 | else | 613 | else |
@@ -596,12 +627,13 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | |||
596 | au_writel(data->blksz - 1, HOST_BLKSIZE(host)); | 627 | au_writel(data->blksz - 1, HOST_BLKSIZE(host)); |
597 | 628 | ||
598 | if (host->flags & HOST_F_DMA) { | 629 | if (host->flags & HOST_F_DMA) { |
630 | #ifdef CONFIG_SOC_AU1200 /* DBDMA */ | ||
599 | int i; | 631 | int i; |
600 | u32 channel = DMA_CHANNEL(host); | 632 | u32 channel = DMA_CHANNEL(host); |
601 | 633 | ||
602 | au1xxx_dbdma_stop(channel); | 634 | au1xxx_dbdma_stop(channel); |
603 | 635 | ||
604 | for(i = 0; i < host->dma.len; i++) { | 636 | for (i = 0; i < host->dma.len; i++) { |
605 | u32 ret = 0, flags = DDMA_FLAGS_NOIE; | 637 | u32 ret = 0, flags = DDMA_FLAGS_NOIE; |
606 | struct scatterlist *sg = &data->sg[i]; | 638 | struct scatterlist *sg = &data->sg[i]; |
607 | int sg_len = sg->length; | 639 | int sg_len = sg->length; |
@@ -611,23 +643,21 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | |||
611 | if (i == host->dma.len - 1) | 643 | if (i == host->dma.len - 1) |
612 | flags = DDMA_FLAGS_IE; | 644 | flags = DDMA_FLAGS_IE; |
613 | 645 | ||
614 | if (host->flags & HOST_F_XMIT){ | 646 | if (host->flags & HOST_F_XMIT) { |
615 | ret = au1xxx_dbdma_put_source_flags(channel, | 647 | ret = au1xxx_dbdma_put_source_flags(channel, |
616 | (void *) sg_virt(sg), len, flags); | 648 | (void *)sg_virt(sg), len, flags); |
617 | } | 649 | } else { |
618 | else { | 650 | ret = au1xxx_dbdma_put_dest_flags(channel, |
619 | ret = au1xxx_dbdma_put_dest_flags(channel, | 651 | (void *)sg_virt(sg), len, flags); |
620 | (void *) sg_virt(sg), | ||
621 | len, flags); | ||
622 | } | 652 | } |
623 | 653 | ||
624 | if (!ret) | 654 | if (!ret) |
625 | goto dataerr; | 655 | goto dataerr; |
626 | 656 | ||
627 | datalen -= len; | 657 | datalen -= len; |
628 | } | 658 | } |
629 | } | 659 | #endif |
630 | else { | 660 | } else { |
631 | host->pio.index = 0; | 661 | host->pio.index = 0; |
632 | host->pio.offset = 0; | 662 | host->pio.offset = 0; |
633 | host->pio.len = datalen; | 663 | host->pio.len = datalen; |
@@ -636,25 +666,21 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) | |||
636 | IRQ_ON(host, SD_CONFIG_TH); | 666 | IRQ_ON(host, SD_CONFIG_TH); |
637 | else | 667 | else |
638 | IRQ_ON(host, SD_CONFIG_NE); | 668 | IRQ_ON(host, SD_CONFIG_NE); |
639 | //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF); | 669 | /* IRQ_ON(host, SD_CONFIG_RA | SD_CONFIG_RF); */ |
640 | } | 670 | } |
641 | 671 | ||
642 | return 0; | 672 | return 0; |
643 | 673 | ||
644 | dataerr: | 674 | dataerr: |
645 | dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir); | 675 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, |
676 | host->dma.dir); | ||
646 | return -ETIMEDOUT; | 677 | return -ETIMEDOUT; |
647 | } | 678 | } |
648 | 679 | ||
649 | /* static void au1xmmc_request | 680 | /* This actually starts a command or data transaction */ |
650 | This actually starts a command or data transaction | ||
651 | */ | ||
652 | |||
653 | static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) | 681 | static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) |
654 | { | 682 | { |
655 | |||
656 | struct au1xmmc_host *host = mmc_priv(mmc); | 683 | struct au1xmmc_host *host = mmc_priv(mmc); |
657 | unsigned int flags = 0; | ||
658 | int ret = 0; | 684 | int ret = 0; |
659 | 685 | ||
660 | WARN_ON(irqs_disabled()); | 686 | WARN_ON(irqs_disabled()); |
@@ -663,11 +689,15 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) | |||
663 | host->mrq = mrq; | 689 | host->mrq = mrq; |
664 | host->status = HOST_S_CMD; | 690 | host->status = HOST_S_CMD; |
665 | 691 | ||
666 | bcsr->disk_leds &= ~(1 << 8); | 692 | /* fail request immediately if no card is present */ |
693 | if (0 == au1xmmc_card_inserted(mmc)) { | ||
694 | mrq->cmd->error = -ENOMEDIUM; | ||
695 | au1xmmc_finish_request(host); | ||
696 | return; | ||
697 | } | ||
667 | 698 | ||
668 | if (mrq->data) { | 699 | if (mrq->data) { |
669 | FLUSH_FIFO(host); | 700 | FLUSH_FIFO(host); |
670 | flags = mrq->data->flags; | ||
671 | ret = au1xmmc_prepare_data(host, mrq->data); | 701 | ret = au1xmmc_prepare_data(host, mrq->data); |
672 | } | 702 | } |
673 | 703 | ||
@@ -682,7 +712,6 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) | |||
682 | 712 | ||
683 | static void au1xmmc_reset_controller(struct au1xmmc_host *host) | 713 | static void au1xmmc_reset_controller(struct au1xmmc_host *host) |
684 | { | 714 | { |
685 | |||
686 | /* Apply the clock */ | 715 | /* Apply the clock */ |
687 | au_writel(SD_ENABLE_CE, HOST_ENABLE(host)); | 716 | au_writel(SD_ENABLE_CE, HOST_ENABLE(host)); |
688 | au_sync_delay(1); | 717 | au_sync_delay(1); |
@@ -712,9 +741,10 @@ static void au1xmmc_reset_controller(struct au1xmmc_host *host) | |||
712 | } | 741 | } |
713 | 742 | ||
714 | 743 | ||
715 | static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | 744 | static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
716 | { | 745 | { |
717 | struct au1xmmc_host *host = mmc_priv(mmc); | 746 | struct au1xmmc_host *host = mmc_priv(mmc); |
747 | u32 config2; | ||
718 | 748 | ||
719 | if (ios->power_mode == MMC_POWER_OFF) | 749 | if (ios->power_mode == MMC_POWER_OFF) |
720 | au1xmmc_set_power(host, 0); | 750 | au1xmmc_set_power(host, 0); |
@@ -726,21 +756,18 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | |||
726 | au1xmmc_set_clock(host, ios->clock); | 756 | au1xmmc_set_clock(host, ios->clock); |
727 | host->clock = ios->clock; | 757 | host->clock = ios->clock; |
728 | } | 758 | } |
729 | } | ||
730 | |||
731 | static void au1xmmc_dma_callback(int irq, void *dev_id) | ||
732 | { | ||
733 | struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id; | ||
734 | |||
735 | /* Avoid spurious interrupts */ | ||
736 | 759 | ||
737 | if (!host->mrq) | 760 | config2 = au_readl(HOST_CONFIG2(host)); |
738 | return; | 761 | switch (ios->bus_width) { |
739 | 762 | case MMC_BUS_WIDTH_4: | |
740 | if (host->flags & HOST_F_STOP) | 763 | config2 |= SD_CONFIG2_WB; |
741 | SEND_STOP(host); | 764 | break; |
742 | 765 | case MMC_BUS_WIDTH_1: | |
743 | tasklet_schedule(&host->data_task); | 766 | config2 &= ~SD_CONFIG2_WB; |
767 | break; | ||
768 | } | ||
769 | au_writel(config2, HOST_CONFIG2(host)); | ||
770 | au_sync(); | ||
744 | } | 771 | } |
745 | 772 | ||
746 | #define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT) | 773 | #define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT) |
@@ -749,245 +776,354 @@ static void au1xmmc_dma_callback(int irq, void *dev_id) | |||
749 | 776 | ||
750 | static irqreturn_t au1xmmc_irq(int irq, void *dev_id) | 777 | static irqreturn_t au1xmmc_irq(int irq, void *dev_id) |
751 | { | 778 | { |
752 | 779 | struct au1xmmc_host *host = dev_id; | |
753 | u32 status; | 780 | u32 status; |
754 | int i, ret = 0; | ||
755 | |||
756 | disable_irq(AU1100_SD_IRQ); | ||
757 | 781 | ||
758 | for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { | 782 | status = au_readl(HOST_STATUS(host)); |
759 | struct au1xmmc_host * host = au1xmmc_hosts[i]; | ||
760 | u32 handled = 1; | ||
761 | 783 | ||
762 | status = au_readl(HOST_STATUS(host)); | 784 | if (!(status & SD_STATUS_I)) |
785 | return IRQ_NONE; /* not ours */ | ||
763 | 786 | ||
764 | if (host->mrq && (status & STATUS_TIMEOUT)) { | 787 | if (status & SD_STATUS_SI) /* SDIO */ |
765 | if (status & SD_STATUS_RAT) | 788 | mmc_signal_sdio_irq(host->mmc); |
766 | host->mrq->cmd->error = -ETIMEDOUT; | ||
767 | 789 | ||
768 | else if (status & SD_STATUS_DT) | 790 | if (host->mrq && (status & STATUS_TIMEOUT)) { |
769 | host->mrq->data->error = -ETIMEDOUT; | 791 | if (status & SD_STATUS_RAT) |
792 | host->mrq->cmd->error = -ETIMEDOUT; | ||
793 | else if (status & SD_STATUS_DT) | ||
794 | host->mrq->data->error = -ETIMEDOUT; | ||
770 | 795 | ||
771 | /* In PIO mode, interrupts might still be enabled */ | 796 | /* In PIO mode, interrupts might still be enabled */ |
772 | IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); | 797 | IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH); |
773 | 798 | ||
774 | //IRQ_OFF(host, SD_CONFIG_TH|SD_CONFIG_RA|SD_CONFIG_RF); | 799 | /* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */ |
775 | tasklet_schedule(&host->finish_task); | 800 | tasklet_schedule(&host->finish_task); |
776 | } | 801 | } |
777 | #if 0 | 802 | #if 0 |
778 | else if (status & SD_STATUS_DD) { | 803 | else if (status & SD_STATUS_DD) { |
779 | 804 | /* Sometimes we get a DD before a NE in PIO mode */ | |
780 | /* Sometimes we get a DD before a NE in PIO mode */ | 805 | if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE)) |
781 | 806 | au1xmmc_receive_pio(host); | |
782 | if (!(host->flags & HOST_F_DMA) && | 807 | else { |
783 | (status & SD_STATUS_NE)) | 808 | au1xmmc_data_complete(host, status); |
784 | au1xmmc_receive_pio(host); | 809 | /* tasklet_schedule(&host->data_task); */ |
785 | else { | ||
786 | au1xmmc_data_complete(host, status); | ||
787 | //tasklet_schedule(&host->data_task); | ||
788 | } | ||
789 | } | 810 | } |
811 | } | ||
790 | #endif | 812 | #endif |
791 | else if (status & (SD_STATUS_CR)) { | 813 | else if (status & SD_STATUS_CR) { |
792 | if (host->status == HOST_S_CMD) | 814 | if (host->status == HOST_S_CMD) |
793 | au1xmmc_cmd_complete(host,status); | 815 | au1xmmc_cmd_complete(host, status); |
794 | } | 816 | |
795 | else if (!(host->flags & HOST_F_DMA)) { | 817 | } else if (!(host->flags & HOST_F_DMA)) { |
796 | if ((host->flags & HOST_F_XMIT) && | 818 | if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT)) |
797 | (status & STATUS_DATA_OUT)) | 819 | au1xmmc_send_pio(host); |
798 | au1xmmc_send_pio(host); | 820 | else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN)) |
799 | else if ((host->flags & HOST_F_RECV) && | 821 | au1xmmc_receive_pio(host); |
800 | (status & STATUS_DATA_IN)) | 822 | |
801 | au1xmmc_receive_pio(host); | 823 | } else if (status & 0x203F3C70) { |
802 | } | 824 | DBG("Unhandled status %8.8x\n", host->pdev->id, |
803 | else if (status & 0x203FBC70) { | 825 | status); |
804 | DBG("Unhandled status %8.8x\n", host->id, status); | ||
805 | handled = 0; | ||
806 | } | ||
807 | |||
808 | au_writel(status, HOST_STATUS(host)); | ||
809 | au_sync(); | ||
810 | |||
811 | ret |= handled; | ||
812 | } | 826 | } |
813 | 827 | ||
814 | enable_irq(AU1100_SD_IRQ); | 828 | au_writel(status, HOST_STATUS(host)); |
815 | return ret; | 829 | au_sync(); |
830 | |||
831 | return IRQ_HANDLED; | ||
816 | } | 832 | } |
817 | 833 | ||
818 | static void au1xmmc_poll_event(unsigned long arg) | 834 | #ifdef CONFIG_SOC_AU1200 |
819 | { | 835 | /* 8bit memory DMA device */ |
820 | struct au1xmmc_host *host = (struct au1xmmc_host *) arg; | 836 | static dbdev_tab_t au1xmmc_mem_dbdev = { |
837 | .dev_id = DSCR_CMD0_ALWAYS, | ||
838 | .dev_flags = DEV_FLAGS_ANYUSE, | ||
839 | .dev_tsize = 0, | ||
840 | .dev_devwidth = 8, | ||
841 | .dev_physaddr = 0x00000000, | ||
842 | .dev_intlevel = 0, | ||
843 | .dev_intpolarity = 0, | ||
844 | }; | ||
845 | static int memid; | ||
821 | 846 | ||
822 | int card = au1xmmc_card_inserted(host); | 847 | static void au1xmmc_dbdma_callback(int irq, void *dev_id) |
823 | int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0; | 848 | { |
849 | struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id; | ||
824 | 850 | ||
825 | if (card != controller) { | 851 | /* Avoid spurious interrupts */ |
826 | host->flags &= ~HOST_F_ACTIVE; | 852 | if (!host->mrq) |
827 | if (card) host->flags |= HOST_F_ACTIVE; | 853 | return; |
828 | mmc_detect_change(host->mmc, 0); | ||
829 | } | ||
830 | 854 | ||
831 | if (host->mrq != NULL) { | 855 | if (host->flags & HOST_F_STOP) |
832 | u32 status = au_readl(HOST_STATUS(host)); | 856 | SEND_STOP(host); |
833 | DBG("PENDING - %8.8x\n", host->id, status); | ||
834 | } | ||
835 | 857 | ||
836 | mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT); | 858 | tasklet_schedule(&host->data_task); |
837 | } | 859 | } |
838 | 860 | ||
839 | static dbdev_tab_t au1xmmc_mem_dbdev = | 861 | static int au1xmmc_dbdma_init(struct au1xmmc_host *host) |
840 | { | ||
841 | DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 8, 0x00000000, 0, 0 | ||
842 | }; | ||
843 | |||
844 | static void au1xmmc_init_dma(struct au1xmmc_host *host) | ||
845 | { | 862 | { |
863 | struct resource *res; | ||
864 | int txid, rxid; | ||
865 | |||
866 | res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0); | ||
867 | if (!res) | ||
868 | return -ENODEV; | ||
869 | txid = res->start; | ||
870 | |||
871 | res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1); | ||
872 | if (!res) | ||
873 | return -ENODEV; | ||
874 | rxid = res->start; | ||
875 | |||
876 | if (!memid) | ||
877 | return -ENODEV; | ||
878 | |||
879 | host->tx_chan = au1xxx_dbdma_chan_alloc(memid, txid, | ||
880 | au1xmmc_dbdma_callback, (void *)host); | ||
881 | if (!host->tx_chan) { | ||
882 | dev_err(&host->pdev->dev, "cannot allocate TX DMA\n"); | ||
883 | return -ENODEV; | ||
884 | } | ||
846 | 885 | ||
847 | u32 rxchan, txchan; | 886 | host->rx_chan = au1xxx_dbdma_chan_alloc(rxid, memid, |
848 | 887 | au1xmmc_dbdma_callback, (void *)host); | |
849 | int txid = au1xmmc_card_table[host->id].tx_devid; | 888 | if (!host->rx_chan) { |
850 | int rxid = au1xmmc_card_table[host->id].rx_devid; | 889 | dev_err(&host->pdev->dev, "cannot allocate RX DMA\n"); |
890 | au1xxx_dbdma_chan_free(host->tx_chan); | ||
891 | return -ENODEV; | ||
892 | } | ||
851 | 893 | ||
852 | /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride | 894 | au1xxx_dbdma_set_devwidth(host->tx_chan, 8); |
853 | of 8 bits. And since devices are shared, we need to create | 895 | au1xxx_dbdma_set_devwidth(host->rx_chan, 8); |
854 | our own to avoid freaking out other devices | ||
855 | */ | ||
856 | 896 | ||
857 | int memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); | 897 | au1xxx_dbdma_ring_alloc(host->tx_chan, AU1XMMC_DESCRIPTOR_COUNT); |
898 | au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT); | ||
858 | 899 | ||
859 | txchan = au1xxx_dbdma_chan_alloc(memid, txid, | 900 | /* DBDMA is good to go */ |
860 | au1xmmc_dma_callback, (void *) host); | 901 | host->flags |= HOST_F_DMA; |
861 | 902 | ||
862 | rxchan = au1xxx_dbdma_chan_alloc(rxid, memid, | 903 | return 0; |
863 | au1xmmc_dma_callback, (void *) host); | 904 | } |
864 | 905 | ||
865 | au1xxx_dbdma_set_devwidth(txchan, 8); | 906 | static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host) |
866 | au1xxx_dbdma_set_devwidth(rxchan, 8); | 907 | { |
908 | if (host->flags & HOST_F_DMA) { | ||
909 | host->flags &= ~HOST_F_DMA; | ||
910 | au1xxx_dbdma_chan_free(host->tx_chan); | ||
911 | au1xxx_dbdma_chan_free(host->rx_chan); | ||
912 | } | ||
913 | } | ||
914 | #endif | ||
867 | 915 | ||
868 | au1xxx_dbdma_ring_alloc(txchan, AU1XMMC_DESCRIPTOR_COUNT); | 916 | static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en) |
869 | au1xxx_dbdma_ring_alloc(rxchan, AU1XMMC_DESCRIPTOR_COUNT); | 917 | { |
918 | struct au1xmmc_host *host = mmc_priv(mmc); | ||
870 | 919 | ||
871 | host->tx_chan = txchan; | 920 | if (en) |
872 | host->rx_chan = rxchan; | 921 | IRQ_ON(host, SD_CONFIG_SI); |
922 | else | ||
923 | IRQ_OFF(host, SD_CONFIG_SI); | ||
873 | } | 924 | } |
874 | 925 | ||
875 | static const struct mmc_host_ops au1xmmc_ops = { | 926 | static const struct mmc_host_ops au1xmmc_ops = { |
876 | .request = au1xmmc_request, | 927 | .request = au1xmmc_request, |
877 | .set_ios = au1xmmc_set_ios, | 928 | .set_ios = au1xmmc_set_ios, |
878 | .get_ro = au1xmmc_card_readonly, | 929 | .get_ro = au1xmmc_card_readonly, |
930 | .get_cd = au1xmmc_card_inserted, | ||
931 | .enable_sdio_irq = au1xmmc_enable_sdio_irq, | ||
879 | }; | 932 | }; |
880 | 933 | ||
881 | static int __devinit au1xmmc_probe(struct platform_device *pdev) | 934 | static int __devinit au1xmmc_probe(struct platform_device *pdev) |
882 | { | 935 | { |
936 | struct mmc_host *mmc; | ||
937 | struct au1xmmc_host *host; | ||
938 | struct resource *r; | ||
939 | int ret; | ||
940 | |||
941 | mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); | ||
942 | if (!mmc) { | ||
943 | dev_err(&pdev->dev, "no memory for mmc_host\n"); | ||
944 | ret = -ENOMEM; | ||
945 | goto out0; | ||
946 | } | ||
883 | 947 | ||
884 | int i, ret = 0; | 948 | host = mmc_priv(mmc); |
885 | 949 | host->mmc = mmc; | |
886 | /* THe interrupt is shared among all controllers */ | 950 | host->platdata = pdev->dev.platform_data; |
887 | ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0); | 951 | host->pdev = pdev; |
888 | 952 | ||
889 | if (ret) { | 953 | ret = -ENODEV; |
890 | printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n", | 954 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
891 | AU1100_SD_IRQ, ret); | 955 | if (!r) { |
892 | return -ENXIO; | 956 | dev_err(&pdev->dev, "no mmio defined\n"); |
957 | goto out1; | ||
893 | } | 958 | } |
894 | 959 | ||
895 | disable_irq(AU1100_SD_IRQ); | 960 | host->ioarea = request_mem_region(r->start, r->end - r->start + 1, |
961 | pdev->name); | ||
962 | if (!host->ioarea) { | ||
963 | dev_err(&pdev->dev, "mmio already in use\n"); | ||
964 | goto out1; | ||
965 | } | ||
896 | 966 | ||
897 | for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { | 967 | host->iobase = (unsigned long)ioremap(r->start, 0x3c); |
898 | struct mmc_host *mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); | 968 | if (!host->iobase) { |
899 | struct au1xmmc_host *host = 0; | 969 | dev_err(&pdev->dev, "cannot remap mmio\n"); |
970 | goto out2; | ||
971 | } | ||
900 | 972 | ||
901 | if (!mmc) { | 973 | r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
902 | printk(DRIVER_NAME "ERROR: no mem for host %d\n", i); | 974 | if (!r) { |
903 | au1xmmc_hosts[i] = 0; | 975 | dev_err(&pdev->dev, "no IRQ defined\n"); |
904 | continue; | 976 | goto out3; |
905 | } | 977 | } |
906 | 978 | ||
907 | mmc->ops = &au1xmmc_ops; | 979 | host->irq = r->start; |
980 | /* IRQ is shared among both SD controllers */ | ||
981 | ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED, | ||
982 | DRIVER_NAME, host); | ||
983 | if (ret) { | ||
984 | dev_err(&pdev->dev, "cannot grab IRQ\n"); | ||
985 | goto out3; | ||
986 | } | ||
908 | 987 | ||
909 | mmc->f_min = 450000; | 988 | mmc->ops = &au1xmmc_ops; |
910 | mmc->f_max = 24000000; | ||
911 | 989 | ||
912 | mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; | 990 | mmc->f_min = 450000; |
913 | mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; | 991 | mmc->f_max = 24000000; |
914 | 992 | ||
915 | mmc->max_blk_size = 2048; | 993 | mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; |
916 | mmc->max_blk_count = 512; | 994 | mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; |
917 | 995 | ||
918 | mmc->ocr_avail = AU1XMMC_OCR; | 996 | mmc->max_blk_size = 2048; |
997 | mmc->max_blk_count = 512; | ||
919 | 998 | ||
920 | host = mmc_priv(mmc); | 999 | mmc->ocr_avail = AU1XMMC_OCR; |
921 | host->mmc = mmc; | 1000 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; |
922 | 1001 | ||
923 | host->id = i; | 1002 | host->status = HOST_S_IDLE; |
924 | host->iobase = au1xmmc_card_table[host->id].iobase; | ||
925 | host->clock = 0; | ||
926 | host->power_mode = MMC_POWER_OFF; | ||
927 | 1003 | ||
928 | host->flags = au1xmmc_card_inserted(host) ? HOST_F_ACTIVE : 0; | 1004 | /* board-specific carddetect setup, if any */ |
929 | host->status = HOST_S_IDLE; | 1005 | if (host->platdata && host->platdata->cd_setup) { |
1006 | ret = host->platdata->cd_setup(mmc, 1); | ||
1007 | if (ret) { | ||
1008 | dev_warn(&pdev->dev, "board CD setup failed\n"); | ||
1009 | mmc->caps |= MMC_CAP_NEEDS_POLL; | ||
1010 | } | ||
1011 | } else | ||
1012 | mmc->caps |= MMC_CAP_NEEDS_POLL; | ||
930 | 1013 | ||
931 | init_timer(&host->timer); | 1014 | tasklet_init(&host->data_task, au1xmmc_tasklet_data, |
1015 | (unsigned long)host); | ||
932 | 1016 | ||
933 | host->timer.function = au1xmmc_poll_event; | 1017 | tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, |
934 | host->timer.data = (unsigned long) host; | 1018 | (unsigned long)host); |
935 | host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT; | ||
936 | 1019 | ||
937 | tasklet_init(&host->data_task, au1xmmc_tasklet_data, | 1020 | #ifdef CONFIG_SOC_AU1200 |
938 | (unsigned long) host); | 1021 | ret = au1xmmc_dbdma_init(host); |
1022 | if (ret) | ||
1023 | printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); | ||
1024 | #endif | ||
939 | 1025 | ||
940 | tasklet_init(&host->finish_task, au1xmmc_tasklet_finish, | 1026 | #ifdef CONFIG_LEDS_CLASS |
941 | (unsigned long) host); | 1027 | if (host->platdata && host->platdata->led) { |
1028 | struct led_classdev *led = host->platdata->led; | ||
1029 | led->name = mmc_hostname(mmc); | ||
1030 | led->brightness = LED_OFF; | ||
1031 | led->default_trigger = mmc_hostname(mmc); | ||
1032 | ret = led_classdev_register(mmc_dev(mmc), led); | ||
1033 | if (ret) | ||
1034 | goto out5; | ||
1035 | } | ||
1036 | #endif | ||
942 | 1037 | ||
943 | spin_lock_init(&host->lock); | 1038 | au1xmmc_reset_controller(host); |
944 | 1039 | ||
945 | if (dma != 0) | 1040 | ret = mmc_add_host(mmc); |
946 | au1xmmc_init_dma(host); | 1041 | if (ret) { |
1042 | dev_err(&pdev->dev, "cannot add mmc host\n"); | ||
1043 | goto out6; | ||
1044 | } | ||
947 | 1045 | ||
948 | au1xmmc_reset_controller(host); | 1046 | platform_set_drvdata(pdev, mmc); |
949 | 1047 | ||
950 | mmc_add_host(mmc); | 1048 | printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X" |
951 | au1xmmc_hosts[i] = host; | 1049 | " (mode=%s)\n", pdev->id, host->iobase, |
1050 | host->flags & HOST_F_DMA ? "dma" : "pio"); | ||
952 | 1051 | ||
953 | add_timer(&host->timer); | 1052 | return 0; /* all ok */ |
954 | 1053 | ||
955 | printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X (mode=%s)\n", | 1054 | out6: |
956 | host->id, host->iobase, dma ? "dma" : "pio"); | 1055 | #ifdef CONFIG_LEDS_CLASS |
957 | } | 1056 | if (host->platdata && host->platdata->led) |
1057 | led_classdev_unregister(host->platdata->led); | ||
1058 | out5: | ||
1059 | #endif | ||
1060 | au_writel(0, HOST_ENABLE(host)); | ||
1061 | au_writel(0, HOST_CONFIG(host)); | ||
1062 | au_writel(0, HOST_CONFIG2(host)); | ||
1063 | au_sync(); | ||
958 | 1064 | ||
959 | enable_irq(AU1100_SD_IRQ); | 1065 | #ifdef CONFIG_SOC_AU1200 |
1066 | au1xmmc_dbdma_shutdown(host); | ||
1067 | #endif | ||
960 | 1068 | ||
961 | return 0; | 1069 | tasklet_kill(&host->data_task); |
1070 | tasklet_kill(&host->finish_task); | ||
1071 | |||
1072 | if (host->platdata && host->platdata->cd_setup && | ||
1073 | !(mmc->caps & MMC_CAP_NEEDS_POLL)) | ||
1074 | host->platdata->cd_setup(mmc, 0); | ||
1075 | |||
1076 | free_irq(host->irq, host); | ||
1077 | out3: | ||
1078 | iounmap((void *)host->iobase); | ||
1079 | out2: | ||
1080 | release_resource(host->ioarea); | ||
1081 | kfree(host->ioarea); | ||
1082 | out1: | ||
1083 | mmc_free_host(mmc); | ||
1084 | out0: | ||
1085 | return ret; | ||
962 | } | 1086 | } |
963 | 1087 | ||
964 | static int __devexit au1xmmc_remove(struct platform_device *pdev) | 1088 | static int __devexit au1xmmc_remove(struct platform_device *pdev) |
965 | { | 1089 | { |
1090 | struct mmc_host *mmc = platform_get_drvdata(pdev); | ||
1091 | struct au1xmmc_host *host; | ||
1092 | |||
1093 | if (mmc) { | ||
1094 | host = mmc_priv(mmc); | ||
966 | 1095 | ||
967 | int i; | 1096 | mmc_remove_host(mmc); |
968 | 1097 | ||
969 | disable_irq(AU1100_SD_IRQ); | 1098 | #ifdef CONFIG_LEDS_CLASS |
1099 | if (host->platdata && host->platdata->led) | ||
1100 | led_classdev_unregister(host->platdata->led); | ||
1101 | #endif | ||
970 | 1102 | ||
971 | for(i = 0; i < AU1XMMC_CONTROLLER_COUNT; i++) { | 1103 | if (host->platdata && host->platdata->cd_setup && |
972 | struct au1xmmc_host *host = au1xmmc_hosts[i]; | 1104 | !(mmc->caps & MMC_CAP_NEEDS_POLL)) |
973 | if (!host) continue; | 1105 | host->platdata->cd_setup(mmc, 0); |
1106 | |||
1107 | au_writel(0, HOST_ENABLE(host)); | ||
1108 | au_writel(0, HOST_CONFIG(host)); | ||
1109 | au_writel(0, HOST_CONFIG2(host)); | ||
1110 | au_sync(); | ||
974 | 1111 | ||
975 | tasklet_kill(&host->data_task); | 1112 | tasklet_kill(&host->data_task); |
976 | tasklet_kill(&host->finish_task); | 1113 | tasklet_kill(&host->finish_task); |
977 | 1114 | ||
978 | del_timer_sync(&host->timer); | 1115 | #ifdef CONFIG_SOC_AU1200 |
1116 | au1xmmc_dbdma_shutdown(host); | ||
1117 | #endif | ||
979 | au1xmmc_set_power(host, 0); | 1118 | au1xmmc_set_power(host, 0); |
980 | 1119 | ||
981 | mmc_remove_host(host->mmc); | 1120 | free_irq(host->irq, host); |
982 | 1121 | iounmap((void *)host->iobase); | |
983 | au1xxx_dbdma_chan_free(host->tx_chan); | 1122 | release_resource(host->ioarea); |
984 | au1xxx_dbdma_chan_free(host->rx_chan); | 1123 | kfree(host->ioarea); |
985 | 1124 | ||
986 | au_writel(0x0, HOST_ENABLE(host)); | 1125 | mmc_free_host(mmc); |
987 | au_sync(); | ||
988 | } | 1126 | } |
989 | |||
990 | free_irq(AU1100_SD_IRQ, 0); | ||
991 | return 0; | 1127 | return 0; |
992 | } | 1128 | } |
993 | 1129 | ||
@@ -1004,21 +1140,31 @@ static struct platform_driver au1xmmc_driver = { | |||
1004 | 1140 | ||
1005 | static int __init au1xmmc_init(void) | 1141 | static int __init au1xmmc_init(void) |
1006 | { | 1142 | { |
1143 | #ifdef CONFIG_SOC_AU1200 | ||
1144 | /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride | ||
1145 | * of 8 bits. And since devices are shared, we need to create | ||
1146 | * our own to avoid freaking out other devices. | ||
1147 | */ | ||
1148 | memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); | ||
1149 | if (!memid) | ||
1150 | printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n"); | ||
1151 | #endif | ||
1007 | return platform_driver_register(&au1xmmc_driver); | 1152 | return platform_driver_register(&au1xmmc_driver); |
1008 | } | 1153 | } |
1009 | 1154 | ||
1010 | static void __exit au1xmmc_exit(void) | 1155 | static void __exit au1xmmc_exit(void) |
1011 | { | 1156 | { |
1157 | #ifdef CONFIG_SOC_AU1200 | ||
1158 | if (memid) | ||
1159 | au1xxx_ddma_del_device(memid); | ||
1160 | #endif | ||
1012 | platform_driver_unregister(&au1xmmc_driver); | 1161 | platform_driver_unregister(&au1xmmc_driver); |
1013 | } | 1162 | } |
1014 | 1163 | ||
1015 | module_init(au1xmmc_init); | 1164 | module_init(au1xmmc_init); |
1016 | module_exit(au1xmmc_exit); | 1165 | module_exit(au1xmmc_exit); |
1017 | 1166 | ||
1018 | #ifdef MODULE | ||
1019 | MODULE_AUTHOR("Advanced Micro Devices, Inc"); | 1167 | MODULE_AUTHOR("Advanced Micro Devices, Inc"); |
1020 | MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX"); | 1168 | MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX"); |
1021 | MODULE_LICENSE("GPL"); | 1169 | MODULE_LICENSE("GPL"); |
1022 | MODULE_ALIAS("platform:au1xxx-mmc"); | 1170 | MODULE_ALIAS("platform:au1xxx-mmc"); |
1023 | #endif | ||
1024 | |||