/* * 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; }