sd卡驱动补丁,这是花了我好几天功夫才搞定的。
已经没有问题了。<br />看来以后都升级内核到2.6.22以后的版本,2.6.21的sd卡有问题。<br />diff -urN linux-2.6.21.old/drivers/mmc/at91_mci.c linux-2.6.21/drivers/mmc/at91_mci.c<br />--- linux-2.6.21.old/drivers/mmc/at91_mci.c 2007-07-09 19:55:27.000000000 +0800<br />+++ linux-2.6.21/drivers/mmc/at91_mci.c 2007-07-10 05:54:03.000000000 +0800<br />@@ -79,9 +79,6 @@<br /> <br /> #define DRIVER_NAME "at91_mci"<br /> <br />-#undef SUPPORT_4WIRE<br />-//#define SUPPORT_4WIRE<br />-<br /> #define FL_SENT_COMMAND (1 << 0)<br /> #define FL_SENT_STOP (1 << 1)<br /> <br />@@ -133,7 +130,7 @@<br /> /*<br /> * Copy from sg to a dma block - used for transfers<br /> */<br />-static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)<br />+static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)<br /> {<br /> unsigned int len, i, size;<br /> unsigned *dmabuf = host->buffer;<br />@@ -182,7 +179,7 @@<br /> /*<br /> * Prepare a dma read<br /> */<br />-static void at91mci_pre_dma_read(struct at91mci_host *host)<br />+static void at91_mci_pre_dma_read(struct at91mci_host *host)<br /> {<br /> int i;<br /> struct scatterlist *sg;<br />@@ -250,7 +247,7 @@<br /> /*<br /> * Handle after a dma read<br /> */<br />-static void at91mci_post_dma_read(struct at91mci_host *host)<br />+static void at91_mci_post_dma_read(struct at91mci_host *host)<br /> {<br /> struct mmc_command *cmd;<br /> struct mmc_data *data;<br />@@ -270,8 +267,6 @@<br /> }<br /> <br /> while (host->in_use_index < host->transfer_index) {<br />- unsigned int *buffer;<br />-<br /> struct scatterlist *sg;<br /> <br /> pr_debug("finishing index %d
", host->in_use_index);<br />@@ -282,29 +277,30 @@<br /> <br /> dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE);<br /> <br />- /* Swap the contents of the buffer */<br />- buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;<br />- pr_debug("buffer = %p, length = %d
", buffer, sg->length);<br />-<br /> data->bytes_xfered += sg->length;<br /> <br /> if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */<br />+ unsigned int *buffer;<br /> int index;<br /> <br />+ /* Swap the contents of the buffer */<br />+ buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;<br />+ pr_debug("buffer = %p, length = %d
", buffer, sg->length);<br />+<br /> for (index = 0; index < (sg->length / 4); index++)<br /> buffer[index] = swab32(buffer[index]);<br />+ kunmap_atomic(buffer, KM_BIO_SRC_IRQ);<br /> }<br /> <br />- kunmap_atomic(buffer, KM_BIO_SRC_IRQ);<br /> flush_dcache_page(sg->page);<br /> }<br /> <br /> /* Is there another transfer to trigger? */<br /> if (host->transfer_index < data->sg_len)<br />- at91mci_pre_dma_read(host);<br />+ at91_mci_pre_dma_read(host);<br /> else {<br />+ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);<br /> at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);<br />- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);<br /> }<br /> <br /> pr_debug("post dma read done
");<br />@@ -325,7 +321,6 @@<br /> <br /> /* Now wait for cmd ready */<br /> at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);<br />- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);<br /> <br /> cmd = host->cmd;<br /> if (!cmd) return;<br />@@ -333,18 +328,55 @@<br /> data = cmd->data;<br /> if (!data) return;<br /> <br />+ if (cmd->data->flags & MMC_DATA_MULTI) {<br />+ pr_debug("multiple write : wait for BLKE...
");<br />+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);<br />+ } <br />+ else<br />+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);<br />+<br /> data->bytes_xfered = host->total_length;<br /> }<br /> <br />+/*Handle after command sent ready*/<br />+static int at91_mci_handle_cmdrdy(struct at91mci_host *host)<br />+{<br />+ if (!host->cmd)<br />+ return 1;<br />+ else if (!host->cmd->data) {<br />+ if (host->flags & FL_SENT_STOP) {<br />+ /*After multi block write, we must wait for NOTBUSY*/<br />+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);<br />+ } else <br />+ return 1;<br />+ } <br />+ else if (host->cmd->data->flags & MMC_DATA_WRITE) {<br />+ /*After sendding multi-block-write command, start DMA transfer*/<br />+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE);<br />+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);<br />+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);<br />+ }<br />+<br />+ /* command not completed, have to wait */<br />+ return 0;<br />+}<br />+<br /> /*<br /> * Enable the controller<br /> */<br /> static void at91_mci_enable(struct at91mci_host *host)<br /> {<br />+ unsigned int mr;<br />+<br /> at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);<br /> at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);<br /> at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);<br />- at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);<br />+ mr = AT91_MCI_PDCMODE | 0x34a;<br />+<br />+ if (cpu_is_at91sam9260() || cpu_is_at91sam9263())<br />+ mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;<br />+<br />+ at91_mci_write(host, AT91_MCI_MR, mr);<br /> <br /> /* use Slot A or B (only one at same time) */<br /> at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);<br />@@ -360,9 +392,8 @@<br /> <br /> /*<br /> * Send a command<br />- * return the interrupts to enable<br /> */<br />-static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)<br />+static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)<br /> {<br /> unsigned int cmdr, mr;<br /> unsigned int block_length;<br />@@ -373,8 +404,7 @@<br /> <br /> host->cmd = cmd;<br /> <br />- /* Not sure if this is needed */<br />-#if 0<br />+/* Needed for leaving busy state before CMD1 */<br /> if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {<br /> pr_debug("Clearing timeout
");<br /> at91_mci_write(host, AT91_MCI_ARGR, 0);<br />@@ -384,7 +414,7 @@<br /> pr_debug("Clearing: SR = %08X
", at91_mci_read(host, AT91_MCI_SR));<br /> }<br /> }<br />-#endif<br />+<br /> cmdr = cmd->opcode;<br /> <br /> if (mmc_resp_type(cmd) == MMC_RSP_NONE)<br />@@ -441,50 +471,50 @@<br /> at91_mci_write(host, ATMEL_PDC_TCR, 0);<br /> at91_mci_write(host, ATMEL_PDC_TNPR, 0);<br /> at91_mci_write(host, ATMEL_PDC_TNCR, 0);<br />-<br />- at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);<br />- at91_mci_write(host, AT91_MCI_CMDR, cmdr);<br />- return AT91_MCI_CMDRDY;<br />- }<br />-<br />- mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */<br />- at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);<br />-<br />- /*<br />- * Disable the PDC controller<br />- */<br />- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);<br />-<br />- if (cmdr & AT91_MCI_TRCMD_START) {<br />- data->bytes_xfered = 0;<br />- host->transfer_index = 0;<br />- host->in_use_index = 0;<br />- if (cmdr & AT91_MCI_TRDIR) {<br />+ ier = AT91_MCI_CMDRDY;<br />+ } <br />+ else <br />+ {<br />+ /* zero block length and PDC mode */<br />+ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;<br />+ at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);<br />+<br />+ /*<br />+ * Disable the PDC controller<br />+ */<br />+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);<br />+<br />+ if (cmdr & AT91_MCI_TRCMD_START) {<br />+ data->bytes_xfered = 0;<br />+ host->transfer_index = 0;<br />+ host->in_use_index = 0;<br />+ if (cmdr & AT91_MCI_TRDIR) {<br /> /*<br />- * Handle a read<br />- */<br />- host->buffer = NULL;<br />- host->total_length = 0;<br />+ * Handle a read<br />+ */<br />+ host->buffer = NULL;<br />+ host->total_length = 0;<br />+ at91_mci_pre_dma_read(host);<br />+ ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;<br />+ } <br />+ else {<br />+ /*<br />+ * Handle a write<br />+ */<br />+ host->total_length = block_length * blocks;<br />+ host->buffer = dma_alloc_coherent(NULL,<br />+ host->total_length,<br />+ &host->physical_address, GFP_KERNEL);<br />+<br />+ at91_mci_sg_to_dma(host, data);<br />+<br />+ pr_debug("Transmitting %d bytes
", host->total_length);<br />+<br />+ at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);<br />+ at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);<br />+ ier = AT91_MCI_CMDRDY;<br />+ } <br /> <br />- at91mci_pre_dma_read(host);<br />- ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;<br />- }<br />- else {<br />- /*<br />- * Handle a write<br />- */<br />- host->total_length = block_length * blocks;<br />- host->buffer = dma_alloc_coherent(NULL,<br />- host->total_length,<br />- &host->physical_address, GFP_KERNEL);<br />-<br />- at91mci_sg_to_dma(host, data);<br />-<br />- pr_debug("Transmitting %d bytes
", host->total_length);<br />-<br />- at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);<br />- at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);<br />- ier = AT91_MCI_TXBUFE;<br /> }<br /> }<br /> <br />@@ -499,39 +529,23 @@<br /> if (cmdr & AT91_MCI_TRCMD_START) {<br /> if (cmdr & AT91_MCI_TRDIR)<br /> at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);<br />- else<br />- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);<br /> }<br />- return ier;<br />-}<br />-<br />-/*<br />- * Wait for a command to complete<br />- */<br />-static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd)<br />-{<br />- unsigned int ier;<br />-<br />- ier = at91_mci_send_command(host, cmd);<br />-<br />- pr_debug("setting ier to %08X
", ier);<br />-<br />- /* Stop on errors or the required value */<br />+ /* Enable selected interrupts */<br /> at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);<br /> }<br /> <br /> /*<br /> * Process the next step in the request<br /> */<br />-static void at91mci_process_next(struct at91mci_host *host)<br />+static void at91_mci_process_next(struct at91mci_host *host)<br /> {<br /> if (!(host->flags & FL_SENT_COMMAND)) {<br /> host->flags |= FL_SENT_COMMAND;<br />- at91mci_process_command(host, host->request->cmd);<br />+ at91_mci_send_command(host, host->request->cmd);<br /> }<br /> else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {<br /> host->flags |= FL_SENT_STOP;<br />- at91mci_process_command(host, host->request->stop);<br />+ at91_mci_send_command(host, host->request->stop);<br /> }<br /> else<br /> mmc_request_done(host->mmc, host->request);<br />@@ -540,7 +554,7 @@<br /> /*<br /> * Handle a command that has been completed<br /> */<br />-static void at91mci_completed_command(struct at91mci_host *host)<br />+static void at91_mci_completed_command(struct at91mci_host *host)<br /> {<br /> struct mmc_command *cmd = host->cmd;<br /> unsigned int status;<br />@@ -584,7 +598,7 @@<br /> else<br /> cmd->error = MMC_ERR_NONE;<br /> <br />- at91mci_process_next(host);<br />+ at91_mci_process_next(host);<br /> }<br /> <br /> /*<br />@@ -596,7 +610,7 @@<br /> host->request = mrq;<br /> host->flags = 0;<br /> <br />- at91mci_process_next(host);<br />+ at91_mci_process_next(host);<br /> }<br /> <br /> /*<br />@@ -698,30 +712,33 @@<br /> pr_debug("TX buffer empty
");<br /> at91_mci_handle_transmitted(host);<br /> }<br />+ if (int_status & AT91_MCI_ENDRX) {<br />+ pr_debug("ENDRX
");<br />+ at91_mci_post_dma_read(host);<br />+ } <br /> <br /> if (int_status & AT91_MCI_RXBUFF) {<br /> pr_debug("RX buffer full
");<br />- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);<br />+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);<br />+ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX);<br />+ completed = 1;<br /> }<br /> <br /> if (int_status & AT91_MCI_ENDTX)<br /> pr_debug("Transmit has ended
");<br /> <br />- if (int_status & AT91_MCI_ENDRX) {<br />- pr_debug("Receive has ended
");<br />- at91mci_post_dma_read(host);<br />- }<br />-<br /> if (int_status & AT91_MCI_NOTBUSY) {<br /> pr_debug("Card is ready
");<br />- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);<br />+ completed = 1;<br /> }<br /> <br /> if (int_status & AT91_MCI_DTIP)<br /> pr_debug("Data transfer in progress
");<br /> <br />- if (int_status & AT91_MCI_BLKE)<br />+ if (int_status & AT91_MCI_BLKE) {<br /> pr_debug("Block transfer has ended
");<br />+ completed = 1;<br />+ }<br /> <br /> if (int_status & AT91_MCI_TXRDY)<br /> pr_debug("Ready to transmit
");<br />@@ -731,14 +748,14 @@<br /> <br /> if (int_status & AT91_MCI_CMDRDY) {<br /> pr_debug("Command ready
");<br />- completed = 1;<br />+ completed = at91_mci_handle_cmdrdy(host);<br /> }<br /> }<br /> <br /> if (completed) {<br /> pr_debug("Completed command
");<br /> at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);<br />- at91mci_completed_command(host);<br />+ at91_mci_completed_command(host);<br /> } else<br /> at91_mci_write(host, AT91_MCI_IDR, int_status);<br /> <br />@@ -831,11 +848,12 @@<br /> host->bus_mode = 0;<br /> host->board = pdev->dev.platform_data;<br /> if (host->board->wire4) {<br />-#ifdef SUPPORT_4WIRE<br />- mmc->caps |= MMC_CAP_4_BIT_DATA;<br />-#else<br />- printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire
");<br />-#endif<br />+<br />+ if (cpu_is_at91sam9260() || cpu_is_at91sam9263())<br />+ mmc->caps |= MMC_CAP_4_BIT_DATA;<br />+ else<br />+ printk("AT91 MMC: 4 wire bus mode not supported"<br />+ " - using 1 wire
");<br /> }<br /> <br /> /*<br />
|
|