From f716ff0bf5140b12035294748aa3401ce816351e Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Fri, 30 May 2008 14:07:47 +0200 Subject: [PATCH] --- yaml --- r: 102168 b: refs/heads/master c: c5a89c6c0805959f813e8342d6f4040860f6d7db h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/mmc/host/at91_mci.c | 48 ++++++++++++++++++++++ trunk/include/asm-arm/arch-at91/at91_mci.h | 4 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index d0744bbfd696..30dcb0a3a139 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e181dce8acab4f7d7c4772d2a8281510d503ab21 +refs/heads/master: c5a89c6c0805959f813e8342d6f4040860f6d7db diff --git a/trunk/drivers/mmc/host/at91_mci.c b/trunk/drivers/mmc/host/at91_mci.c index fce171c7c67e..e9242110ce2e 100644 --- a/trunk/drivers/mmc/host/at91_mci.c +++ b/trunk/drivers/mmc/host/at91_mci.c @@ -130,6 +130,43 @@ struct at91mci_host struct timer_list timer; }; +/* + * Reset the controller and restore most of the state + */ +static void at91_reset_host(struct at91mci_host *host) +{ + unsigned long flags; + u32 mr; + u32 sdcr; + u32 dtor; + u32 imr; + + local_irq_save(flags); + imr = at91_mci_read(host, AT91_MCI_IMR); + + at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); + + /* save current state */ + mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; + sdcr = at91_mci_read(host, AT91_MCI_SDCR); + dtor = at91_mci_read(host, AT91_MCI_DTOR); + + /* reset the controller */ + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); + + /* restore state */ + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(host, AT91_MCI_MR, mr); + at91_mci_write(host, AT91_MCI_SDCR, sdcr); + at91_mci_write(host, AT91_MCI_DTOR, dtor); + at91_mci_write(host, AT91_MCI_IER, imr); + + /* make sure sdio interrupts will fire */ + at91_mci_read(host, AT91_MCI_SR); + + local_irq_restore(flags); +} + static void at91_timeout_timer(unsigned long data) { struct at91mci_host *host; @@ -148,6 +185,7 @@ static void at91_timeout_timer(unsigned long data) host->request->cmd->error = -ETIMEDOUT; } + at91_reset_host(host); mmc_request_done(host->mmc, host->request); } } @@ -512,6 +550,11 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command mr |= AT91_MCI_PDCMODE; at91_mci_write(host, AT91_MCI_MR, mr); + if (!cpu_is_at91rm9200()) + at91_mci_write(host, AT91_MCI_BLKR, + AT91_MCI_BLKR_BCNT(blocks) | + AT91_MCI_BLKR_BLKLEN(block_length)); + /* * Disable the PDC controller */ @@ -584,6 +627,11 @@ static void at91_mci_process_next(struct at91mci_host *host) at91_mci_send_command(host, host->request->stop); } else { del_timer(&host->timer); + /* the at91rm9200 mci controller hangs after some transfers, + * and the workaround is to reset it after each transfer. + */ + if (cpu_is_at91rm9200()) + at91_reset_host(host); mmc_request_done(host->mmc, host->request); } } diff --git a/trunk/include/asm-arm/arch-at91/at91_mci.h b/trunk/include/asm-arm/arch-at91/at91_mci.h index 1551fc24eb43..400ec10014b4 100644 --- a/trunk/include/asm-arm/arch-at91/at91_mci.h +++ b/trunk/include/asm-arm/arch-at91/at91_mci.h @@ -75,6 +75,10 @@ #define AT91_MCI_TRTYP_MULTIPLE (1 << 19) #define AT91_MCI_TRTYP_STREAM (2 << 19) +#define AT91_MCI_BLKR 0x18 /* Block Register */ +#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */ +#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block lenght */ + #define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */ #define AT91_MCR_RDR 0x30 /* Receive Data Register */ #define AT91_MCR_TDR 0x34 /* Transmit Data Register */