/* Handle after a dma read */ static void at91mci_post_dma_read(struct at91mci_host* host) { struct mmc_command* cmd; struct mmc_data* data; DBG("post dma read\n"); cmd = host->cmd; if (!cmd) { DBG("no command\n"); return; } data = cmd->data; if (!data) { DBG("no data\n"); return; } while (host->in_use_index < host->transfer_index) { unsigned int* buffer; int index; int len; struct scatterlist* sg; DBG("finishing index %d\n", host->in_use_index); sg = &data->sg[host->in_use_index++]; DBG("Unmapping page %08X\n", sg->dma_address); 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; DBG("buffer = %p, length = %d\n", buffer, sg->length); data->bytes_xfered += sg->length; len = sg->length / 4; for (index = 0; index < len; index++) { buffer[index] = BYTE_SWAP4(buffer[index]); } flush_dcache_page(sg->page); kunmap_atomic(sg->page, KM_BIO_SRC_IRQ); } /* Is there another transfer to trigger? */ if (host->transfer_index < data->sg_len) { at91mci_pre_dma_read(host); } else { controller->MCI_IER = AT91C_MCI_RXBUFF; controller->MCI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; } DBG("post dma read done\n"); }
/* * Handle after a dma read */ static void at91mci_post_dma_read(struct at91mci_host *host) { struct mmc_command *cmd; struct mmc_data *data; pr_debug("post dma read\n"); cmd = host->cmd; if (!cmd) { pr_debug("no command\n"); return; } data = cmd->data; if (!data) { pr_debug("no data\n"); return; } while (host->in_use_index < host->transfer_index) { unsigned int *buffer; struct scatterlist *sg; pr_debug("finishing index %d\n", host->in_use_index); sg = &data->sg[host->in_use_index++]; pr_debug("Unmapping page %08X\n", sg->dma_address); 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 */ int index; for (index = 0; index < (sg->length / 4); index++) buffer[index] = swab32(buffer[index]); } 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); else { at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); } pr_debug("post dma read done\n"); }
/* * Send a command * return the interrupts to enable */ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) { unsigned int cmdr, mr; unsigned int block_length; struct mmc_data *data = cmd->data; unsigned int blocks; unsigned int ier = 0; host->cmd = cmd; /* Not sure if this is needed */ #if 0 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); at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { /* spin */ 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) cmdr |= AT91_MCI_RSPTYP_NONE; else { /* if a response is expected then allow maximum response latancy */ cmdr |= AT91_MCI_MAXLAT; /* set 136 bit response for R2, 48 bit response otherwise */ if (mmc_resp_type(cmd) == MMC_RSP_R2) cmdr |= AT91_MCI_RSPTYP_136; else cmdr |= AT91_MCI_RSPTYP_48; } if (data) { block_length = data->blksz; blocks = data->blocks; /* always set data start - also set direction flag for read */ if (data->flags & MMC_DATA_READ) cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); else if (data->flags & MMC_DATA_WRITE) cmdr |= AT91_MCI_TRCMD_START; if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; if (data->flags & MMC_DATA_MULTI) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } else { block_length = 0; blocks = 0; } if (cmd->opcode == MMC_STOP_TRANSMISSION) cmdr |= AT91_MCI_TRCMD_STOP; if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdr |= AT91_MCI_OPDCMD; /* * Set the arguments and send the command */ pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); if (!data) { at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); at91_mci_write(host, AT91_PDC_RPR, 0); at91_mci_write(host, AT91_PDC_RCR, 0); at91_mci_write(host, AT91_PDC_RNPR, 0); at91_mci_write(host, AT91_PDC_RNCR, 0); at91_mci_write(host, AT91_PDC_TPR, 0); at91_mci_write(host, AT91_PDC_TCR, 0); at91_mci_write(host, AT91_PDC_TNPR, 0); at91_mci_write(host, AT91_PDC_TNCR, 0); 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, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_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); at91_mci_write(host, AT91_PDC_TPR, host->physical_address); at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4); ier = AT91_MCI_TXBUFE; } } /* * Send the command and then enable the PDC - not the other way round as * the data sheet says */ at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); at91_mci_write(host, AT91_MCI_CMDR, cmdr); if (cmdr & AT91_MCI_TRCMD_START) { if (cmdr & AT91_MCI_TRDIR) at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN); else at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN); } return ier; }
/* * Send a command * return the interrupts to enable */ static unsigned int at91rm9200_mci_send_command(struct at91mci_host* host, struct mmc_command* cmd) { unsigned int cmdr; unsigned int block_length; struct mmc_data* data = cmd->data; struct mmc_host* mmc = host->mmc; unsigned int blocks; unsigned int ier = 0; host->cmd = cmd; /* Not sure if this is needed */ #if 0 if ((controller->MCI_SR & AT91C_MCI_RTOE) && (cmd->opcode == 1)) { DBG("Clearing timeout\n"); controller->MCI_ARGR = 0; controller->MCI_CMDR = AT91C_MCI_OPDCMD; while (!(controller->MCI_SR & AT91C_MCI_CMDRDY)) { /* spin */ DBG("Clearing: SR = %08X\n", controller->MCI_SR); } } #endif cmdr = commands[cmd->opcode]; if (data) { block_length = 1 << data->blksz_bits; blocks = data->blocks; } else { block_length = 0; blocks = 0; } if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN) { cmdr |= AT91C_MCI_OPDCMD; } /* * Set the arguments and send the command */ DBG("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", cmd->opcode, cmdr, cmd->arg, blocks, block_length, controller->MCI_MR); if (!data) { controller->MCI_PTCR = (AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS); controller->MCI_RPR = 0; controller->MCI_RCR = 0; controller->MCI_RNPR = 0; controller->MCI_RNCR = 0; controller->MCI_TPR = 0; controller->MCI_TCR = 0; controller->MCI_TNPR = 0; controller->MCI_TNCR = 0; controller->MCI_ARGR = cmd->arg; controller->MCI_CMDR = cmdr; return AT91C_MCI_CMDRDY; } controller->MCI_MR &= ~0xFFFF8000; /* zero block length and PDC mode */ controller->MCI_MR |= (block_length << 16) | AT91C_MCI_PDCMODE; /* * Disable the PDC controller */ controller->MCI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; if (cmdr & AT91C_MCI_TRCMD_START) { data->bytes_xfered = 0; host->transfer_index = 0; host->in_use_index = 0; if (cmdr & AT91C_MCI_TRDIR) { /* * Handle a read */ host->buffer = NULL; host->total_length = 0; at91mci_pre_dma_read(host); ier = AT91C_MCI_ENDRX /* | AT91C_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); DBG("Transmitting %d bytes\n", host->total_length); controller->MCI_TPR = host->physical_address; controller->MCI_TCR = host->total_length / 4; ier = AT91C_MCI_TXBUFE; } } /* * Send the command and then enable the PDC - not the other way round as * the data sheet says */ controller->MCI_ARGR = cmd->arg; controller->MCI_CMDR = cmdr; if (cmdr & AT91C_MCI_TRCMD_START) { if (cmdr & AT91C_MCI_TRDIR) { controller->MCI_PTCR = AT91C_PDC_RXTEN; } else { controller->MCI_PTCR = AT91C_PDC_TXTEN; } } return ier; }