diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/at91_mci.c | 222 | ||||
-rw-r--r-- | drivers/mmc/host/au1xmmc.c | 3 | ||||
-rw-r--r-- | drivers/mmc/host/omap.c | 24 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.h | 22 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 10 |
5 files changed, 132 insertions, 149 deletions
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index e37943c314c..28c881895ab 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -78,8 +78,6 @@ #define DRIVER_NAME "at91_mci" -#undef SUPPORT_4WIRE - #define FL_SENT_COMMAND (1 << 0) #define FL_SENT_STOP (1 << 1) @@ -131,7 +129,7 @@ struct at91mci_host /* * Copy from sg to a dma block - used for transfers */ -static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) +static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) { unsigned int len, i, size; unsigned *dmabuf = host->buffer; @@ -180,7 +178,7 @@ static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data /* * Prepare a dma read */ -static void at91mci_pre_dma_read(struct at91mci_host *host) +static void at91_mci_pre_dma_read(struct at91mci_host *host) { int i; struct scatterlist *sg; @@ -248,7 +246,7 @@ static void at91mci_pre_dma_read(struct at91mci_host *host) /* * Handle after a dma read */ -static void at91mci_post_dma_read(struct at91mci_host *host) +static void at91_mci_post_dma_read(struct at91mci_host *host) { struct mmc_command *cmd; struct mmc_data *data; @@ -268,8 +266,6 @@ static void at91mci_post_dma_read(struct at91mci_host *host) } while (host->in_use_index < host->transfer_index) { - unsigned int *buffer; - struct scatterlist *sg; pr_debug("finishing index %d\n", host->in_use_index); @@ -280,29 +276,31 @@ static void at91mci_post_dma_read(struct at91mci_host *host) dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE); - /* Swap the contents of the buffer */ - buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; - pr_debug("buffer = %p, length = %d\n", buffer, sg->length); - data->bytes_xfered += sg->length; if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ + unsigned int *buffer; int index; + /* Swap the contents of the buffer */ + buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; + pr_debug("buffer = %p, length = %d\n", buffer, sg->length); + for (index = 0; index < (sg->length / 4); index++) buffer[index] = swab32(buffer[index]); + + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); } - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); flush_dcache_page(sg->page); } /* Is there another transfer to trigger? */ if (host->transfer_index < data->sg_len) - at91mci_pre_dma_read(host); + at91_mci_pre_dma_read(host); else { + at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); } pr_debug("post dma read done\n"); @@ -323,7 +321,6 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) /* Now wait for cmd ready */ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); cmd = host->cmd; if (!cmd) return; @@ -331,18 +328,53 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host) data = cmd->data; if (!data) return; + if (cmd->data->flags & MMC_DATA_MULTI) { + pr_debug("multiple write : wait for BLKE...\n"); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); + } else + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); + data->bytes_xfered = host->total_length; } +/*Handle after command sent ready*/ +static int at91_mci_handle_cmdrdy(struct at91mci_host *host) +{ + if (!host->cmd) + return 1; + else if (!host->cmd->data) { + if (host->flags & FL_SENT_STOP) { + /*After multi block write, we must wait for NOTBUSY*/ + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); + } else return 1; + } else if (host->cmd->data->flags & MMC_DATA_WRITE) { + /*After sendding multi-block-write command, start DMA transfer*/ + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE); + at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); + } + + /* command not completed, have to wait */ + return 0; +} + + /* * Enable the controller */ static void at91_mci_enable(struct at91mci_host *host) { + unsigned int mr; + at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); - at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a); + mr = AT91_MCI_PDCMODE | 0x34a; + + if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) + mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; + + at91_mci_write(host, AT91_MCI_MR, mr); /* use Slot A or B (only one at same time) */ at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); @@ -358,9 +390,8 @@ static void at91_mci_disable(struct at91mci_host *host) /* * Send a command - * return the interrupts to enable */ -static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) +static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) { unsigned int cmdr, mr; unsigned int block_length; @@ -371,8 +402,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ host->cmd = cmd; - /* Not sure if this is needed */ -#if 0 + /* Needed for leaving busy state before CMD1 */ if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { pr_debug("Clearing timeout\n"); at91_mci_write(host, AT91_MCI_ARGR, 0); @@ -382,7 +412,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); } } -#endif + cmdr = cmd->opcode; if (mmc_resp_type(cmd) == MMC_RSP_NONE) @@ -417,7 +447,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ blocks = 0; } - if (cmd->opcode == MMC_STOP_TRANSMISSION) + if (host->flags & FL_SENT_STOP) cmdr |= AT91_MCI_TRCMD_STOP; if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) @@ -439,50 +469,48 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ at91_mci_write(host, ATMEL_PDC_TCR, 0); at91_mci_write(host, ATMEL_PDC_TNPR, 0); at91_mci_write(host, ATMEL_PDC_TNCR, 0); + ier = AT91_MCI_CMDRDY; + } else { + /* zero block length and PDC mode */ + mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; + at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); - at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); - at91_mci_write(host, AT91_MCI_CMDR, cmdr); - return AT91_MCI_CMDRDY; - } - - mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ - at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); - - /* - * Disable the PDC controller - */ - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - - if (cmdr & AT91_MCI_TRCMD_START) { - data->bytes_xfered = 0; - host->transfer_index = 0; - host->in_use_index = 0; - if (cmdr & AT91_MCI_TRDIR) { - /* - * Handle a read - */ - host->buffer = NULL; - host->total_length = 0; - - at91mci_pre_dma_read(host); - ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; - } - else { - /* - * Handle a write - */ - host->total_length = block_length * blocks; - host->buffer = dma_alloc_coherent(NULL, - host->total_length, - &host->physical_address, GFP_KERNEL); - - at91mci_sg_to_dma(host, data); - - pr_debug("Transmitting %d bytes\n", host->total_length); + /* + * Disable the PDC controller + */ + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); - at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); - ier = AT91_MCI_TXBUFE; + if (cmdr & AT91_MCI_TRCMD_START) { + data->bytes_xfered = 0; + host->transfer_index = 0; + host->in_use_index = 0; + if (cmdr & AT91_MCI_TRDIR) { + /* + * Handle a read + */ + host->buffer = NULL; + host->total_length = 0; + + at91_mci_pre_dma_read(host); + ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; + } + else { + /* + * Handle a write + */ + host->total_length = block_length * blocks; + host->buffer = dma_alloc_coherent(NULL, + host->total_length, + &host->physical_address, GFP_KERNEL); + + at91_mci_sg_to_dma(host, data); + + pr_debug("Transmitting %d bytes\n", host->total_length); + + at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); + at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); + ier = AT91_MCI_CMDRDY; + } } } @@ -497,39 +525,24 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_ if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); - else - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } - return ier; -} - -/* - * Wait for a command to complete - */ -static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd) -{ - unsigned int ier; - - ier = at91_mci_send_command(host, cmd); - - pr_debug("setting ier to %08X\n", ier); - /* Stop on errors or the required value */ + /* Enable selected interrupts */ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); } /* * Process the next step in the request */ -static void at91mci_process_next(struct at91mci_host *host) +static void at91_mci_process_next(struct at91mci_host *host) { if (!(host->flags & FL_SENT_COMMAND)) { host->flags |= FL_SENT_COMMAND; - at91mci_process_command(host, host->request->cmd); + at91_mci_send_command(host, host->request->cmd); } else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { host->flags |= FL_SENT_STOP; - at91mci_process_command(host, host->request->stop); + at91_mci_send_command(host, host->request->stop); } else mmc_request_done(host->mmc, host->request); @@ -538,7 +551,7 @@ static void at91mci_process_next(struct at91mci_host *host) /* * Handle a command that has been completed */ -static void at91mci_completed_command(struct at91mci_host *host) +static void at91_mci_completed_command(struct at91mci_host *host) { struct mmc_command *cmd = host->cmd; unsigned int status; @@ -563,8 +576,7 @@ static void at91mci_completed_command(struct at91mci_host *host) if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) { - if ((status & AT91_MCI_RCRCE) && - ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) { + if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { cmd->error = MMC_ERR_NONE; } else { @@ -584,7 +596,7 @@ static void at91mci_completed_command(struct at91mci_host *host) else cmd->error = MMC_ERR_NONE; - at91mci_process_next(host); + at91_mci_process_next(host); } /* @@ -596,7 +608,7 @@ static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->request = mrq; host->flags = 0; - at91mci_process_next(host); + at91_mci_process_next(host); } /* @@ -699,29 +711,33 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) at91_mci_handle_transmitted(host); } + if (int_status & AT91_MCI_ENDRX) { + pr_debug("ENDRX\n"); + at91_mci_post_dma_read(host); + } + if (int_status & AT91_MCI_RXBUFF) { pr_debug("RX buffer full\n"); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); + at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); + completed = 1; } if (int_status & AT91_MCI_ENDTX) pr_debug("Transmit has ended\n"); - if (int_status & AT91_MCI_ENDRX) { - pr_debug("Receive has ended\n"); - at91mci_post_dma_read(host); - } - if (int_status & AT91_MCI_NOTBUSY) { pr_debug("Card is ready\n"); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); + completed = 1; } if (int_status & AT91_MCI_DTIP) pr_debug("Data transfer in progress\n"); - if (int_status & AT91_MCI_BLKE) + if (int_status & AT91_MCI_BLKE) { pr_debug("Block transfer has ended\n"); + completed = 1; + } if (int_status & AT91_MCI_TXRDY) pr_debug("Ready to transmit\n"); @@ -731,14 +747,14 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) if (int_status & AT91_MCI_CMDRDY) { pr_debug("Command ready\n"); - completed = 1; + completed = at91_mci_handle_cmdrdy(host); } } if (completed) { pr_debug("Completed command\n"); at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - at91mci_completed_command(host); + at91_mci_completed_command(host); } else at91_mci_write(host, AT91_MCI_IDR, int_status); @@ -831,11 +847,11 @@ static int __init at91_mci_probe(struct platform_device *pdev) host->bus_mode = 0; host->board = pdev->dev.platform_data; if (host->board->wire4) { -#ifdef SUPPORT_4WIRE - mmc->caps |= MMC_CAP_4_BIT_DATA; -#else - printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); -#endif + if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) + mmc->caps |= MMC_CAP_4_BIT_DATA; + else + printk("AT91 MMC: 4 wire bus mode not supported" + " - using 1 wire\n"); } /* diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index f967226d750..52b63f11ddd 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -76,8 +76,7 @@ const struct { #endif }; -#define AU1XMMC_CONTROLLER_COUNT \ - (sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0])) +#define AU1XMMC_CONTROLLER_COUNT (ARRAY_SIZE(au1xmmc_card_table)) /* This array stores pointers for the hosts (used by the IRQ handler) */ struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT]; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 1914e65d4db..b0824a38f42 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -522,28 +522,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) } if (status & OMAP_MMC_STAT_CARD_ERR) { - if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) { - u32 response = OMAP_MMC_READ(host, RSP6) - | (OMAP_MMC_READ(host, RSP7) << 16); - /* STOP sometimes sets must-ignore bits */ - if (!(response & (R1_CC_ERROR - | R1_ILLEGAL_COMMAND - | R1_COM_CRC_ERROR))) { - end_command = 1; - continue; - } - } - - dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n", + dev_dbg(mmc_dev(host->mmc), + "ignoring card status error (CMD%d)\n", host->cmd->opcode); - if (host->cmd) { - host->cmd->error = MMC_ERR_FAILED; - end_command = 1; - } - if (host->data) { - host->data->error = MMC_ERR_FAILED; - transfer_error = 1; - } + end_command = 1; } /* diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index 1b163220df2..df17c281278 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -1,25 +1,3 @@ -#undef MMC_STRPCL -#undef MMC_STAT -#undef MMC_CLKRT -#undef MMC_SPI -#undef MMC_CMDAT -#undef MMC_RESTO -#undef MMC_RDTO -#undef MMC_BLKLEN -#undef MMC_NOB -#undef MMC_PRTBUF -#undef MMC_I_MASK -#undef END_CMD_RES -#undef PRG_DONE -#undef DATA_TRAN_DONE -#undef MMC_I_REG -#undef MMC_CMD -#undef MMC_ARGH -#undef MMC_ARGL -#undef MMC_RES -#undef MMC_RXFIFO -#undef MMC_TXFIFO - #define MMC_STRPCL 0x0000 #define STOP_CLOCK (1 << 0) #define START_CLOCK (2 << 0) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a359efdd77e..10d15c39d00 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -70,6 +70,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, }, + { + .vendor = PCI_VENDOR_ID_ENE, + .device = PCI_DEVICE_ID_ENE_CB712_SD_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -1022,7 +1030,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS); } - intmask &= SDHCI_INT_BUS_POWER; + intmask &= ~SDHCI_INT_BUS_POWER; if (intmask) { printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", |