aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMarc Pignat <marc.pignat@hevs.ch>2008-05-30 08:07:47 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-07-15 08:14:42 -0400
commitc5a89c6c0805959f813e8342d6f4040860f6d7db (patch)
treeb6f0e3071d44196d1dd8dc5775e42996185a49b9 /drivers/mmc
parente181dce8acab4f7d7c4772d2a8281510d503ab21 (diff)
mmc: at91_mci: avoid timeouts
The at91 mci controller internal state machine seems to often crash. This can be fixed by resetting the controller after each command for at91rm9200 and by setting the MCI_BLKR register on at91sam926*. Signed-off-by: Marc Pignat <marc.pignat@hevs.ch> Signed-off-by: Hans J Koch <hjk@linutronix.de> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/at91_mci.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index fce171c7c67e..e9242110ce2e 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -130,6 +130,43 @@ struct at91mci_host
130 struct timer_list timer; 130 struct timer_list timer;
131}; 131};
132 132
133/*
134 * Reset the controller and restore most of the state
135 */
136static void at91_reset_host(struct at91mci_host *host)
137{
138 unsigned long flags;
139 u32 mr;
140 u32 sdcr;
141 u32 dtor;
142 u32 imr;
143
144 local_irq_save(flags);
145 imr = at91_mci_read(host, AT91_MCI_IMR);
146
147 at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
148
149 /* save current state */
150 mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
151 sdcr = at91_mci_read(host, AT91_MCI_SDCR);
152 dtor = at91_mci_read(host, AT91_MCI_DTOR);
153
154 /* reset the controller */
155 at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
156
157 /* restore state */
158 at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
159 at91_mci_write(host, AT91_MCI_MR, mr);
160 at91_mci_write(host, AT91_MCI_SDCR, sdcr);
161 at91_mci_write(host, AT91_MCI_DTOR, dtor);
162 at91_mci_write(host, AT91_MCI_IER, imr);
163
164 /* make sure sdio interrupts will fire */
165 at91_mci_read(host, AT91_MCI_SR);
166
167 local_irq_restore(flags);
168}
169
133static void at91_timeout_timer(unsigned long data) 170static void at91_timeout_timer(unsigned long data)
134{ 171{
135 struct at91mci_host *host; 172 struct at91mci_host *host;
@@ -148,6 +185,7 @@ static void at91_timeout_timer(unsigned long data)
148 host->request->cmd->error = -ETIMEDOUT; 185 host->request->cmd->error = -ETIMEDOUT;
149 } 186 }
150 187
188 at91_reset_host(host);
151 mmc_request_done(host->mmc, host->request); 189 mmc_request_done(host->mmc, host->request);
152 } 190 }
153} 191}
@@ -512,6 +550,11 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
512 mr |= AT91_MCI_PDCMODE; 550 mr |= AT91_MCI_PDCMODE;
513 at91_mci_write(host, AT91_MCI_MR, mr); 551 at91_mci_write(host, AT91_MCI_MR, mr);
514 552
553 if (!cpu_is_at91rm9200())
554 at91_mci_write(host, AT91_MCI_BLKR,
555 AT91_MCI_BLKR_BCNT(blocks) |
556 AT91_MCI_BLKR_BLKLEN(block_length));
557
515 /* 558 /*
516 * Disable the PDC controller 559 * Disable the PDC controller
517 */ 560 */
@@ -584,6 +627,11 @@ static void at91_mci_process_next(struct at91mci_host *host)
584 at91_mci_send_command(host, host->request->stop); 627 at91_mci_send_command(host, host->request->stop);
585 } else { 628 } else {
586 del_timer(&host->timer); 629 del_timer(&host->timer);
630 /* the at91rm9200 mci controller hangs after some transfers,
631 * and the workaround is to reset it after each transfer.
632 */
633 if (cpu_is_at91rm9200())
634 at91_reset_host(host);
587 mmc_request_done(host->mmc, host->request); 635 mmc_request_done(host->mmc, host->request);
588 } 636 }
589} 637}