static void goldfish_mmc_start_command(struct goldfish_mmc_host *host, struct mmc_command *cmd) { u32 cmdreg; u32 resptype; u32 cmdtype; host->cmd = cmd; resptype = 0; cmdtype = 0; /* Our hardware needs to know exact type */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: case MMC_RSP_R1B: /* resp 1, 1b, 6, 7 */ resptype = 1; break; case MMC_RSP_R2: resptype = 2; break; case MMC_RSP_R3: resptype = 3; break; default: dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd)); break; } if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { cmdtype = OMAP_MMC_CMDTYPE_ADTC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) { cmdtype = OMAP_MMC_CMDTYPE_BC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) { cmdtype = OMAP_MMC_CMDTYPE_BCR; } else { cmdtype = OMAP_MMC_CMDTYPE_AC; } cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdreg |= 1 << 6; if (cmd->flags & MMC_RSP_BUSY) cmdreg |= 1 << 11; if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; GOLDFISH_MMC_WRITE(host, MMC_ARG, cmd->arg); GOLDFISH_MMC_WRITE(host, MMC_CMD, cmdreg); }
static void nuc970_emmc_send_stop(struct nuc970_emmc_host *host, struct mmc_command *cmd) { unsigned int csr; unsigned int block_length; unsigned int blocks; host->cmd = cmd; emmc_host = host; emmc_state = 0; emmc_state_xfer = 0; if (nuc970_emmc_read(REG_NAND_FMICSR) != FMICSR_EMMCEN) nuc970_emmc_write(REG_NAND_FMICSR, FMICSR_EMMCEN); csr = nuc970_emmc_read(REG_EMMCCSR) & 0xff00c080; csr = csr | (cmd->opcode << 8) | EMMCCSR_CO_EN; // set command code and enable command out emmc_event |= EMMC_EVENT_CMD_OUT; if (host->bus_mode == MMC_BUS_WIDTH_4) csr |= EMMCCSR_DBW; if (mmc_resp_type(cmd) != MMC_RSP_NONE) { /* if a response is expected then allow maximum response latancy */ /* set 136 bit response for R2, 48 bit response otherwise */ if (mmc_resp_type(cmd) == MMC_RSP_R2) { csr |= EMMCCSR_R2_EN; emmc_event |= EMMC_EVENT_RSP2_IN; } else { csr |= EMMCCSR_RI_EN; emmc_event |= EMMC_EVENT_RSP_IN; } nuc970_emmc_write(REG_EMMCISR, EMMCISR_RITO_IF); emmc_ri_timeout = 0; nuc970_emmc_write(REG_EMMCTMOUT, 0xffff); } nuc970_emmc_write(REG_EMMCIER, nuc970_emmc_read(REG_EMMCIER) & ~EMMCIER_BLKD_IE); //disable SD interrupt block_length = 0; blocks = 0; nuc970_emmc_write(REG_EMMCARG, cmd->arg); nuc970_emmc_write(REG_EMMCCSR, csr); emmc_send_cmd = 1; wake_up_interruptible(&emmc_event_wq); mmc_request_done(host->mmc, host->request); }
static int usdhi6_cmd_flags(struct usdhi6_host *host) { struct mmc_request *mrq = host->mrq; struct mmc_command *cmd = mrq->cmd; u16 opc = cmd->opcode; if (host->app_cmd) { host->app_cmd = false; opc |= USDHI6_SD_CMD_APP; } if (mrq->data) { opc |= USDHI6_SD_CMD_DATA; if (mrq->data->flags & MMC_DATA_READ) opc |= USDHI6_SD_CMD_READ; if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || (cmd->opcode == SD_IO_RW_EXTENDED && mrq->data->blocks > 1)) { opc |= USDHI6_SD_CMD_MULTI; if (!mrq->stop) opc |= USDHI6_SD_CMD_CMD12_AUTO_OFF; } switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: opc |= USDHI6_SD_CMD_MODE_RSP_NONE; break; case MMC_RSP_R1: opc |= USDHI6_SD_CMD_MODE_RSP_R1; break; case MMC_RSP_R1B: opc |= USDHI6_SD_CMD_MODE_RSP_R1B; break; case MMC_RSP_R2: opc |= USDHI6_SD_CMD_MODE_RSP_R2; break; case MMC_RSP_R3: opc |= USDHI6_SD_CMD_MODE_RSP_R3; break; default: dev_warn(mmc_dev(host->mmc), "Unknown response type %d\n", mmc_resp_type(cmd)); return -EINVAL; } } return opc; }
static void hi_mci_cmd_done(struct himci_host *host, unsigned int stat) { unsigned int i; struct mmc_command *cmd = host->cmd; himci_trace(2, "begin"); himci_assert(host); himci_assert(cmd); host->cmd = NULL; for (i = 0; i < 4; i++) { if (mmc_resp_type(cmd) == MMC_RSP_R2) cmd->resp[i] = himci_readl(host->base + MCI_RESP3 - i * 0x4); else cmd->resp[i] = himci_readl(host->base + MCI_RESP0 + i * 0x4); } if (stat & RTO_INT_STATUS) { cmd->error = -ETIMEDOUT; himci_trace(3, "irq cmd status stat = 0x%x is timeout error!", stat); } else if (stat & (RCRC_INT_STATUS | RE_INT_STATUS)) { cmd->error = -EILSEQ; himci_trace(3, "irq cmd status stat = 0x%x is response error!", stat); } }
static int sdhi_boot_request(void __iomem *base, struct mmc_command *cmd) { int err, c = cmd->opcode; switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: c |= RESP_NONE; break; case MMC_RSP_R1: c |= RESP_R1; break; case MMC_RSP_R1B: c |= RESP_R1B; break; case MMC_RSP_R2: c |= RESP_R2; break; case MMC_RSP_R3: c |= RESP_R3; break; default: return -EINVAL; } /* No interrupts so this may not be cleared */ sd_ctrl_write32(base, CTL_STATUS, ~TMIO_STAT_CMDRESPEND); sd_ctrl_write32(base, CTL_IRQ_MASK, TMIO_STAT_CMDRESPEND | sd_ctrl_read32(base, CTL_IRQ_MASK)); sd_ctrl_write32(base, CTL_ARG_REG, cmd->arg); sd_ctrl_write16(base, CTL_SD_CMD, c); sd_ctrl_write32(base, CTL_IRQ_MASK, ~(TMIO_STAT_CMDRESPEND | ALL_ERROR) & sd_ctrl_read32(base, CTL_IRQ_MASK)); err = sdhi_boot_wait_resp_end(base); if (err) return err; cmd->resp[0] = sd_ctrl_read32(base, CTL_RESPONSE); return 0; }
static void tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) { void *base = host->ctl_base; struct mmc_data *data = host->data; int c = cmd->opcode; if(cmd->opcode == MMC_STOP_TRANSMISSION) { writew(0x001, host->ctl_base + TMIO_CTRL_STOP_INTERNAL_ACTION_REG); return; } switch(mmc_resp_type(cmd)) { case MMC_RSP_NONE: c |= RESP_NONE; break; case MMC_RSP_R1: c |= RESP_R1; break; case MMC_RSP_R1B: c |= RESP_R1B; break; case MMC_RSP_R2: c |= RESP_R2; break; case MMC_RSP_R3: c |= RESP_R3; break; default: DBG("Unknown response type %d\n", mmc_resp_type(cmd)); } host->cmd = cmd; // FIXME - this seems to be ok comented out but the spec say this bit should // be set when issuing app commands... the upper MC code doesnt help us // here, though. // if(cmd->flags & MMC_FLAG_ACMD) // c |= APP_CMD; if(data) { c |= DATA_PRESENT; if(data->blocks > 1) { writew(0x100, host->ctl_base + TMIO_CTRL_STOP_INTERNAL_ACTION_REG); c |= TRANSFER_MULTI; } if(data->flags & MMC_DATA_READ) c |= TRANSFER_READ; } enable_mmc_irqs(host, TMIO_MASK_CMD); /* Fire off the command */ write_long_reg(cmd->arg, base + TMIO_CTRL_ARG_REG_BASE); writew(c, base + TMIO_CTRL_CMD_REG); }
/* * Handle a command that has been completed */ static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status) { struct mmc_command *cmd = host->cmd; struct mmc_data *data = cmd->data; at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); if (host->buffer) { dma_unmap_single(NULL, host->physical_address, host->total_length, DMA_TO_DEVICE); kfree(host->buffer); host->buffer = NULL; } pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n", status, at91_mci_read(host, AT91_MCI_SR), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (status & AT91_MCI_ERRORS) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { cmd->error = 0; } else { if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) { if (data) { if (status & AT91_MCI_DTOE) data->error = -ETIMEDOUT; else if (status & AT91_MCI_DCRCE) data->error = -EILSEQ; } } else { if (status & AT91_MCI_RTOE) cmd->error = -ETIMEDOUT; else if (status & AT91_MCI_RCRCE) cmd->error = -EILSEQ; else cmd->error = -EIO; } pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n", cmd->error, data ? data->error : 0, cmd->opcode, cmd->retries); } } else cmd->error = 0; at91_mci_process_next(host); }
static void rcv_resp(struct ak880xmci_host *host, struct mmc_command *cmd) { cmd->resp[0] = mci_read(host, MMC_RESP1); cmd->resp[1] = mci_read(host, MMC_RESP2); cmd->resp[2] = mci_read(host, MMC_RESP3); cmd->resp[3] = mci_read(host, MMC_RESP4); if (mmc_resp_type(cmd) & MMC_RSP_OPCODE) { int rsp_opcode = mci_read(host, MMC_CMD_RESP); /* dbg("rsp_opcode(%d)", rsp_opcode); */ } }
static void mxs_mmc_ac(struct mxs_mmc_host *host) { struct mxs_ssp *ssp = &host->ssp; struct mmc_command *cmd = host->cmd; struct dma_async_tx_descriptor *desc; u32 ignore_crc, get_resp, long_resp; u32 ctrl0, cmd0, cmd1; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? BM_SSP_CTRL0_GET_RESP : 0; long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? BM_SSP_CTRL0_LONG_RESP : 0; ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp; cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); cmd1 = cmd->arg; if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } ssp->ssp_pio_words[0] = ctrl0; ssp->ssp_pio_words[1] = cmd0; ssp->ssp_pio_words[2] = cmd1; ssp->dma_dir = DMA_NONE; ssp->slave_dirn = DMA_TRANS_NONE; desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK); if (!desc) goto out; dmaengine_submit(desc); dma_async_issue_pending(ssp->dmach); return; out: dev_warn(mmc_dev(host->mmc), "%s: failed to prep dma\n", __func__); }
static void mxs_mmc_request_done(struct mxs_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct mmc_data *data = host->data; struct mmc_request *mrq = host->mrq; struct mxs_ssp *ssp = &host->ssp; if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { if (mmc_resp_type(cmd) & MMC_RSP_136) { cmd->resp[3] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); cmd->resp[2] = readl(ssp->base + HW_SSP_SDRESP1(ssp)); cmd->resp[1] = readl(ssp->base + HW_SSP_SDRESP2(ssp)); cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP3(ssp)); } else { cmd->resp[0] = readl(ssp->base + HW_SSP_SDRESP0(ssp)); } } if (data) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ssp->dma_dir); /* * If there was an error on any block, we mark all * data blocks as being in error. */ if (!data->error) data->bytes_xfered = data->blocks * data->blksz; else data->bytes_xfered = 0; host->data = NULL; if (mrq->stop) { mxs_mmc_start_cmd(host, mrq->stop); return; } } host->mrq = NULL; mmc_request_done(host->mmc, mrq); }
/* * This function sets up the SDHC registers in order to issue a command. * * @param priv Pointer to MMC/SD priv structure * @param cmd Pointer to MMC/SD command structure * @param cmdat Value to store in the Command and Data Control registers */ static void mxcmci_start_cmd(struct mxcmci_priv *priv, struct mmc_command *cmd, unsigned int cmdat) { unsigned long flags; int timeout; int ret; WARN_ON(priv->cmd != NULL); priv->cmd = cmd; switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; break; case RSP_TYPE(MMC_RSP_R3): cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; break; case RSP_TYPE(MMC_RSP_R2): cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; break; default: /* No Response required */ break; } if (cmd->opcode == MMC_GO_IDLE_STATE) cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ if (priv->host->ios.bus_width == MMC_BUS_WIDTH_4) cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; local_irq_save(flags); mxcmci_start_clock(priv); __raw_writel(cmd->opcode, priv->base + MMC_CMD); __raw_writel(cmd->arg, priv->base + MMC_ARG); __raw_writel(cmdat, priv->base + MMC_CMD_DAT_CONT); local_irq_restore(flags); timeout = wait_for_completion_timeout(&priv->comp_cmd_done, msecs_to_jiffies(1000)); if (timeout == 0) { dev_err(priv->host->parent, "wait cmd_done timeout\n"); cmd->error = -ETIMEDOUT; } ret = mxcmci_cmd_done(priv, 0); if (ret) return; }
static void usdhi6_resp_read(struct usdhi6_host *host) { struct mmc_command *cmd = host->mrq->cmd; u32 *rsp = cmd->resp, tmp = 0; int i; /* * RSP10 39-8 * RSP32 71-40 * RSP54 103-72 * RSP76 127-104 * R2-type response: * resp[0] = r[127..96] * resp[1] = r[95..64] * resp[2] = r[63..32] * resp[3] = r[31..0] * Other responses: * resp[0] = r[39..8] */ if (mmc_resp_type(cmd) == MMC_RSP_NONE) return; if (!(host->irq_status & USDHI6_SD_INFO1_RSP_END)) { dev_err(mmc_dev(host->mmc), "CMD%d: response expected but is missing!\n", cmd->opcode); return; } if (mmc_resp_type(cmd) & MMC_RSP_136) for (i = 0; i < 4; i++) { if (i) rsp[3 - i] = tmp >> 24; tmp = usdhi6_read(host, USDHI6_SD_RSP10 + i * 8); rsp[3 - i] |= tmp << 8; } else if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd) { struct cvm_mmc_cr_type *cr; u8 hardware_ctype, hardware_rtype; u8 desired_ctype = 0, desired_rtype = 0; struct cvm_mmc_cr_mods r; cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f); hardware_ctype = cr->ctype; hardware_rtype = cr->rtype; if (cmd->opcode == MMC_GEN_CMD) hardware_ctype = (cmd->arg & 1) ? 1 : 2; switch (mmc_cmd_type(cmd)) { case MMC_CMD_ADTC: desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1; break; case MMC_CMD_AC: case MMC_CMD_BC: case MMC_CMD_BCR: desired_ctype = 0; break; } switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: desired_rtype = 0; break; case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */ case MMC_RSP_R1B: desired_rtype = 1; break; case MMC_RSP_R2: desired_rtype = 2; break; case MMC_RSP_R3: /* MMC_RSP_R4 */ desired_rtype = 3; break; } r.ctype_xor = desired_ctype ^ hardware_ctype; r.rtype_xor = desired_rtype ^ hardware_rtype; return r; }
/* * Handle a command that has been completed */ static void at91_mci_completed_command(struct at91mci_host *host) { struct mmc_command *cmd = host->cmd; unsigned int status; at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); if (host->buffer) { dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); host->buffer = NULL; } status = at91_mci_read(host, AT91_MCI_SR); pr_debug("Status = %08X [%08X %08X %08X %08X]\n", status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); if (status & AT91_MCI_ERRORS) { if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { cmd->error = 0; } else { if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) cmd->error = -ETIMEDOUT; else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) cmd->error = -EILSEQ; else cmd->error = -EIO; pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n", cmd->error, cmd->opcode, cmd->retries); } } else cmd->error = 0; at91_mci_process_next(host); }
static int hi_mci_exec_cmd(struct himci_host *host, struct mmc_command *cmd, struct mmc_data *data) { union cmd_arg_s cmd_regs; himci_trace(2, "begin"); himci_assert(host); himci_assert(cmd); host->cmd = cmd; himci_writel(cmd->arg, host->base + MCI_CMDARG); cmd_regs.cmd_arg = himci_readl(host->base + MCI_CMD); if (data) { cmd_regs.bits.data_transfer_expected = 1; if (data->flags & (MMC_DATA_WRITE | MMC_DATA_READ)) cmd_regs.bits.transfer_mode = 0; if (data->flags & MMC_DATA_STREAM) cmd_regs.bits.transfer_mode = 1; if (data->flags & MMC_DATA_WRITE) cmd_regs.bits.read_write = 1; else if (data->flags & MMC_DATA_READ) cmd_regs.bits.read_write = 0; } else { cmd_regs.bits.data_transfer_expected = 0; cmd_regs.bits.transfer_mode = 0; cmd_regs.bits.read_write = 0; } if (cmd == host->mrq->stop) { cmd_regs.bits.stop_abort_cmd = 1; cmd_regs.bits.wait_prvdata_complete = 0; } else { cmd_regs.bits.stop_abort_cmd = 0; cmd_regs.bits.wait_prvdata_complete = 1; } switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: cmd_regs.bits.response_expect = 0; cmd_regs.bits.response_length = 0; cmd_regs.bits.check_response_crc = 0; break; case MMC_RSP_R1: case MMC_RSP_R1B: cmd_regs.bits.response_expect = 1; cmd_regs.bits.response_length = 0; cmd_regs.bits.check_response_crc = 1; break; case MMC_RSP_R2: cmd_regs.bits.response_expect = 1; cmd_regs.bits.response_length = 1; cmd_regs.bits.check_response_crc = 1; break; case MMC_RSP_R3: cmd_regs.bits.response_expect = 1; cmd_regs.bits.response_length = 0; cmd_regs.bits.check_response_crc = 0; break; default: himci_error("hi_mci: unhandled response type %02x\n", mmc_resp_type(cmd)); return -EINVAL; } himci_trace(3, "send cmd of card is cmd->opcode = %d ", cmd->opcode); if (cmd->opcode == MMC_GO_IDLE_STATE) cmd_regs.bits.send_initialization = 1; else cmd_regs.bits.send_initialization = 0; cmd_regs.bits.card_number = 0; cmd_regs.bits.cmd_index = cmd->opcode; cmd_regs.bits.send_auto_stop = 0; cmd_regs.bits.start_cmd = 1; cmd_regs.bits.update_clk_reg_only = 0; himci_writel(cmd_regs.cmd_arg, host->base + MCI_CMD); if (hi_mci_wait_cmd(host) != 0) { himci_trace(3, "send card cmd is failed!"); return -EINVAL; } return 0; }
static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, struct mmc_command *cmd) { struct rtsx_pcr *pcr = host->pcr; u8 cmd_idx = (u8)cmd->opcode; u32 arg = cmd->arg; int err = 0; int timeout = 100; int i; u8 *ptr; int stat_idx = 0; u8 rsp_type; int rsp_len = 5; bool clock_toggled = false; dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", __func__, cmd_idx, arg); /* Response type: * R0 * R1, R5, R6, R7 * R1b * R2 * R3, R4 */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: rsp_type = SD_RSP_TYPE_R0; rsp_len = 0; break; case MMC_RSP_R1: rsp_type = SD_RSP_TYPE_R1; break; case MMC_RSP_R1 & ~MMC_RSP_CRC: rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; break; case MMC_RSP_R1B: rsp_type = SD_RSP_TYPE_R1b; break; case MMC_RSP_R2: rsp_type = SD_RSP_TYPE_R2; rsp_len = 16; break; case MMC_RSP_R3: rsp_type = SD_RSP_TYPE_R3; break; default: dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); err = -EINVAL; goto out; } if (rsp_type == SD_RSP_TYPE_R1b) timeout = 3000; if (cmd->opcode == SD_SWITCH_VOLTAGE) { err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); if (err < 0) goto out; clock_toggled = true; } rtsx_pci_init_cmd(pcr); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END | SD_STAT_IDLE, SD_TRANSFER_END | SD_STAT_IDLE); if (rsp_type == SD_RSP_TYPE_R2) { /* Read data from ping-pong buffer */ for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); stat_idx = 16; } else if (rsp_type != SD_RSP_TYPE_R0) { /* Read data from SD_CMDx registers */ for (i = SD_CMD0; i <= SD_CMD4; i++) rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); stat_idx = 5; } rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); err = rtsx_pci_send_cmd(pcr, timeout); if (err < 0) { sd_print_debug_regs(host); sd_clear_error(host); dev_dbg(sdmmc_dev(host), "rtsx_pci_send_cmd error (err = %d)\n", err); goto out; } if (rsp_type == SD_RSP_TYPE_R0) { err = 0; goto out; } /* Eliminate returned value of CHECK_REG_CMD */ ptr = rtsx_pci_get_cmd_data(pcr) + 1; /* Check (Start,Transmission) bit of Response */ if ((ptr[0] & 0xC0) != 0) { err = -EILSEQ; dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); goto out; } /* Check CRC7 */ if (!(rsp_type & SD_NO_CHECK_CRC7)) { if (ptr[stat_idx] & SD_CRC7_ERR) { err = -EILSEQ; dev_dbg(sdmmc_dev(host), "CRC7 error\n"); goto out; } } if (rsp_type == SD_RSP_TYPE_R2) { /* * The controller offloads the last byte {CRC-7, end bit 1'b1} * of response type R2. Assign dummy CRC, 0, and end bit to the * byte(ptr[16], goes into the LSB of resp[3] later). */ ptr[16] = 1; for (i = 0; i < 4; i++) { cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", i, cmd->resp[i]); } } else { cmd->resp[0] = get_unaligned_be32(ptr + 1); dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", cmd->resp[0]); } out: cmd->error = err; if (err && clock_toggled) rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); }
static void mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) { u32 cmdreg; u32 resptype; u32 cmdtype; host->cmd = cmd; resptype = 0; cmdtype = 0; /* Our hardware needs to know exact type */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: case MMC_RSP_R1B: /* resp 1, 1b, 6, 7 */ resptype = 1; break; case MMC_RSP_R2: resptype = 2; break; case MMC_RSP_R3: resptype = 3; break; default: dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd)); break; } if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { cmdtype = OMAP_MMC_CMDTYPE_ADTC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) { cmdtype = OMAP_MMC_CMDTYPE_BC; } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) { cmdtype = OMAP_MMC_CMDTYPE_BCR; } else { cmdtype = OMAP_MMC_CMDTYPE_AC; } cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); if (host->current_slot->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdreg |= 1 << 6; if (cmd->flags & MMC_RSP_BUSY) cmdreg |= 1 << 11; if (host->data && !(host->data->flags & MMC_DATA_WRITE)) cmdreg |= 1 << 15; mod_timer(&host->cmd_abort_timer, jiffies + HZ/2); OMAP_MMC_WRITE(host, CTO, 200); OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff); OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16); OMAP_MMC_WRITE(host, IE, OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | OMAP_MMC_STAT_END_OF_DATA); OMAP_MMC_WRITE(host, CMD, cmdreg); }
static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, struct mmc_command *cmd, struct mmc_data *data) { u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: mmccmd |= SD_CMD_RT_1; break; case MMC_RSP_R1B: mmccmd |= SD_CMD_RT_1B; break; case MMC_RSP_R2: mmccmd |= SD_CMD_RT_2; break; case MMC_RSP_R3: mmccmd |= SD_CMD_RT_3; break; default: printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", mmc_resp_type(cmd)); return -EINVAL; } if (data) { if (data->flags & MMC_DATA_READ) { if (data->blocks > 1) mmccmd |= SD_CMD_CT_4; else mmccmd |= SD_CMD_CT_2; } else if (data->flags & MMC_DATA_WRITE) { if (data->blocks > 1) mmccmd |= SD_CMD_CT_3; else mmccmd |= SD_CMD_CT_1; } } au_writel(cmd->arg, HOST_CMDARG(host)); au_sync(); if (wait) IRQ_OFF(host, SD_CONFIG_CR); au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host)); au_sync(); /* Wait for the command to go on the line */ while (au_readl(HOST_CMD(host)) & SD_CMD_GO) /* nop */; /* Wait for the command to come back */ if (wait) { u32 status = au_readl(HOST_STATUS(host)); while (!(status & SD_STATUS_CR)) status = au_readl(HOST_STATUS(host)); /* Clear the CR status */ au_writel(SD_STATUS_CR, HOST_STATUS(host)); IRQ_ON(host, SD_CONFIG_CR); } return 0; }
/* Send the ac command to the device */ static void stmp3xxx_mmc_ac(struct stmp3xxx_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; u32 ignore_crc, resp, long_resp; u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? BM_SSP_CTRL0_GET_RESP : 0; long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? BM_SSP_CTRL0_LONG_RESP : 0; dma_desc->command->cmd = BM_APBH_CHn_CMD_WAIT4ENDCMD | BM_APBH_CHn_CMD_SEMAPHORE | BM_APBH_CHn_CMD_IRQONCMPLT | BF(0, APBH_CHn_CMD_XFER_COUNT) | BF(3, APBH_CHn_CMD_CMDWORDS) | BF(0, APBH_CHn_CMD_COMMAND); ssp_ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | long_resp | resp; ssp_cmd0 = BF(cmd->opcode, SSP_CMD0_CMD); ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); dma_desc->command->pio_words[0] = ssp_ctrl0; dma_desc->command->pio_words[1] = ssp_cmd0; dma_desc->command->pio_words[2] = ssp_cmd1; stmp3xxx_dma_reset_channel(host->dmach); init_completion(&host->dma_done); stmp3xxx_dma_go(host->dmach, dma_desc, 1); wait_for_completion(&host->dma_done); switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: while (__raw_readl(host->ssp_base + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN) continue; break; case MMC_RSP_R1: case MMC_RSP_R1B: case MMC_RSP_R3: cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); break; case MMC_RSP_R2: cmd->resp[3] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); cmd->resp[2] = __raw_readl(host->ssp_base + HW_SSP_SDRESP1); cmd->resp[1] = __raw_readl(host->ssp_base + HW_SSP_SDRESP2); cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP3); break; default: dev_warn(host->dev, "Unsupported response type 0x%x\n", mmc_resp_type(cmd)); BUG(); break; } cmd->error = stmp3xxx_mmc_cmd_error(host->status); if (stmp3xxx_dma_running(host->dmach)) dev_dbg(host->dev, "DMA command not finished\n"); if (cmd->error) { dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); stmp3xxx_dma_reset_channel(host->dmach); } }
/* * Send a command */ static void 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; /* 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); 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)); } } 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) { if ( data->blksz & 0x3 ) { pr_debug("Unsupported block size\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } 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->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } else { block_length = 0; blocks = 0; } if (host->flags & FL_SENT_STOP) 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, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); at91_mci_write(host, ATMEL_PDC_RPR, 0); at91_mci_write(host, ATMEL_PDC_RCR, 0); at91_mci_write(host, ATMEL_PDC_RNPR, 0); at91_mci_write(host, ATMEL_PDC_RNCR, 0); at91_mci_write(host, ATMEL_PDC_TPR, 0); 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); /* * 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; 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; } } } /* * 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, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } /* Enable selected interrupts */ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); }
static void 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; 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)) { pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); } } cmdr = cmd->opcode; if (mmc_resp_type(cmd) == MMC_RSP_NONE) cmdr |= AT91_MCI_RSPTYP_NONE; else { cmdr |= AT91_MCI_MAXLAT; if (mmc_resp_type(cmd) == MMC_RSP_R2) cmdr |= AT91_MCI_RSPTYP_136; else cmdr |= AT91_MCI_RSPTYP_48; } if (data) { if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) { if (data->blksz & 0x3) { pr_debug("Unsupported block size\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } if (data->flags & MMC_DATA_STREAM) { pr_debug("Stream commands not supported\n"); cmd->error = -EINVAL; mmc_request_done(host->mmc, host->request); return; } } block_length = data->blksz; blocks = data->blocks; 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 (cmd->opcode == SD_IO_RW_EXTENDED) { cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; } else { if (data->flags & MMC_DATA_STREAM) cmdr |= AT91_MCI_TRTYP_STREAM; if (data->blocks > 1) cmdr |= AT91_MCI_TRTYP_MULTIPLE; } } else { block_length = 0; blocks = 0; } if (host->flags & FL_SENT_STOP) cmdr |= AT91_MCI_TRCMD_STOP; if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdr |= AT91_MCI_OPDCMD; 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, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); at91_mci_write(host, ATMEL_PDC_RPR, 0); at91_mci_write(host, ATMEL_PDC_RCR, 0); at91_mci_write(host, ATMEL_PDC_RNPR, 0); at91_mci_write(host, ATMEL_PDC_RNCR, 0); at91_mci_write(host, ATMEL_PDC_TPR, 0); 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 { mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff; mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0; mr |= (block_length << 16); mr |= AT91_MCI_PDCMODE; at91_mci_write(host, AT91_MCI_MR, mr); if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261())) at91_mci_write(host, AT91_MCI_BLKR, AT91_MCI_BLKR_BCNT(blocks) | AT91_MCI_BLKR_BLKLEN(block_length)); 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) { host->total_length = 0; at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address); at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? (blocks * block_length) : (blocks * block_length) / 4); at91_mci_write(host, ATMEL_PDC_RNPR, 0); at91_mci_write(host, ATMEL_PDC_RNCR, 0); ier = AT91_MCI_ENDRX ; } else { host->total_length = block_length * blocks; if (at91mci_is_mci1rev2xx()) if (host->total_length < 12) host->total_length = 12; 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, (data->blksz & 0x3) ? host->total_length : host->total_length / 4); ier = AT91_MCI_CMDRDY; } } } 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, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); }
static void jz_mmc_start_cmd(struct jz_mmc_host *host, struct mmc_command *cmd, unsigned int cmdat) { u32 timeout = 0x3fffff; unsigned int stat; struct jz_mmc_host *hst = host; WARN_ON(host->cmd != NULL); host->cmd = cmd; /* stop MMC clock */ jz_mmc_stop_clock(); /* mask interrupts */ REG_MSC_IMASK = 0xff; /* clear status */ REG_MSC_IREG = 0xff; if (cmd->flags & MMC_RSP_BUSY) cmdat |= MSC_CMDAT_BUSY; #define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ cmdat |= MSC_CMDAT_RESPONSE_R1; r_type = 1; break; case RSP_TYPE(MMC_RSP_R3): cmdat |= MSC_CMDAT_RESPONSE_R3; r_type = 1; break; case RSP_TYPE(MMC_RSP_R2): cmdat |= MSC_CMDAT_RESPONSE_R2; r_type = 2; break; default: break; } REG_MSC_CMD = cmd->opcode; /* Set argument */ #ifdef CONFIG_JZ_MMC_BUS_1 if (cmd->opcode == 6) { /* set 1 bit sd card bus*/ if (cmd->arg ==2) REG_MSC_ARG = 0; /* set 1 bit mmc card bus*/ if (cmd->arg == 0x3b70101) REG_MSC_ARG = 0x3b70001; } else REG_MSC_ARG = cmd->arg; #else REG_MSC_ARG = cmd->arg; #endif /* Set command */ REG_MSC_CMDAT = cmdat; /* Send command */ jz_mmc_start_clock(); while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) ; REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */ if (cmd->opcode == 12) { while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE)) ; REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ } if (!mmc_slot_enable) { /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when * card was removed. We force to return here. */ cmd->error = -ETIMEDOUT; jz_mmc_finish_request(hst, hst->mrq); return; } if (SD_IO_SEND_OP_COND == cmd->opcode) { /* * Don't support SDIO card currently. */ cmd->error = -ETIMEDOUT; jz_mmc_finish_request(hst, hst->mrq); return; } /* Check for status */ stat = REG_MSC_STAT; jz_mmc_cmd_done(hst, stat); if (host->data) { if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) #ifdef USE_DMA jz_mmc_tx_setup_data(host, host->data); #else jz_mmc_send_pio(host); else jz_mmc_receive_pio(host); #endif }
static void mmc_davinci_start_command(struct mmc_davinci_host *host, struct mmc_command *cmd) { u32 cmdreg = 0; u32 resptype = 0; u32 cmdtype = 0; unsigned long flags; host->cmd = cmd; resptype = 0; cmdtype = 0; switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* resp 1, resp 1b */ resptype = 1; break; case RSP_TYPE(MMC_RSP_R2): resptype = 2; break; case RSP_TYPE(MMC_RSP_R3): resptype = 3; break; default: break; } /* Protocol layer does not provide command type, but our hardware * needs it! * any data transfer means adtc type (but that information is not * in command structure, so we flagged it into host struct.) * However, telling bc, bcr and ac apart based on response is * not foolproof: * CMD0 = bc = resp0 CMD15 = ac = resp0 * CMD2 = bcr = resp2 CMD10 = ac = resp2 * * Resolve to best guess with some exception testing: * resp0 -> bc, except CMD15 = ac * rest are ac, except if opendrain */ if (host->data_dir) cmdtype = DAVINCI_MMC_CMDTYPE_ADTC; else if (resptype == 0 && cmd->opcode != 15) cmdtype = DAVINCI_MMC_CMDTYPE_BC; else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) cmdtype = DAVINCI_MMC_CMDTYPE_BCR; else cmdtype = DAVINCI_MMC_CMDTYPE_AC; /* * Set command Busy or not * Linux core sending BUSY which is not defined for cmd 24 * as per mmc standard */ if (cmd->flags & MMC_RSP_BUSY) if (cmd->opcode != 24) cmdreg = cmdreg | (1 << 8); /* Set command index */ cmdreg |= cmd->opcode; /* Setting initialize clock */ if (cmd->opcode == 0) cmdreg = cmdreg | (1 << 14); /* Set for generating DMA Xfer event */ if ((host->do_dma == 1) && (host->data != NULL) && ((cmd->opcode == 18) || (cmd->opcode == 25) || (cmd->opcode == 24) || (cmd->opcode == 17))) cmdreg = cmdreg | (1 << 16); /* Setting whether command involves data transfer or not */ if (cmdtype == DAVINCI_MMC_CMDTYPE_ADTC) cmdreg = cmdreg | (1 << 13); /* Setting whether stream or block transfer */ if (cmd->flags & MMC_DATA_STREAM) cmdreg = cmdreg | (1 << 12); /* Setting whether data read or write */ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) cmdreg = cmdreg | (1 << 11); /* Setting response type */ cmdreg = cmdreg | (resptype << 9); if (host->bus_mode == MMC_BUSMODE_PUSHPULL) cmdreg = cmdreg | (1 << 7); /* set Command timeout */ DAVINCI_MMC_WRITEW(host, TOR, 0xFFFF); /* Enable interrupt */ if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) { if (host->do_dma != 1) DAVINCI_MMC_WRITEW(host, IM, (DAVINCI_MMC_EVENT_EOFCMD | DAVINCI_MMC_EVENT_WRITE | DAVINCI_MMC_EVENT_ERROR_CMDCRC | DAVINCI_MMC_EVENT_ERROR_DATACRC | DAVINCI_MMC_EVENT_ERROR_CMDTIMEOUT | DAVINCI_MMC_EVENT_ERROR_DATATIMEOUT | DAVINCI_MMC_EVENT_BLOCK_XFERRED)); else DAVINCI_MMC_WRITEW(host, IM, (DAVINCI_MMC_EVENT_EOFCMD | DAVINCI_MMC_EVENT_ERROR_CMDCRC | DAVINCI_MMC_EVENT_ERROR_DATACRC | DAVINCI_MMC_EVENT_ERROR_CMDTIMEOUT | DAVINCI_MMC_EVENT_ERROR_DATATIMEOUT | DAVINCI_MMC_EVENT_BLOCK_XFERRED)); } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) { if (host->do_dma != 1) DAVINCI_MMC_WRITEW(host, IM, (DAVINCI_MMC_EVENT_EOFCMD | DAVINCI_MMC_EVENT_READ | DAVINCI_MMC_EVENT_ERROR_CMDCRC | DAVINCI_MMC_EVENT_ERROR_DATACRC | DAVINCI_MMC_EVENT_ERROR_CMDTIMEOUT | DAVINCI_MMC_EVENT_ERROR_DATATIMEOUT | DAVINCI_MMC_EVENT_BLOCK_XFERRED)); else DAVINCI_MMC_WRITEW(host, IM, (DAVINCI_MMC_EVENT_EOFCMD | DAVINCI_MMC_EVENT_ERROR_CMDCRC | DAVINCI_MMC_EVENT_ERROR_DATACRC | DAVINCI_MMC_EVENT_ERROR_CMDTIMEOUT | DAVINCI_MMC_EVENT_ERROR_DATATIMEOUT | DAVINCI_MMC_EVENT_BLOCK_XFERRED)); } else DAVINCI_MMC_WRITEW(host, IM, (DAVINCI_MMC_EVENT_EOFCMD | DAVINCI_MMC_EVENT_ERROR_CMDCRC | DAVINCI_MMC_EVENT_ERROR_DATACRC | DAVINCI_MMC_EVENT_ERROR_CMDTIMEOUT | DAVINCI_MMC_EVENT_ERROR_DATATIMEOUT)); /* * It is required by controoler b4 WRITE command that * FIFO should be populated with 32 bytes */ if ((host->data_dir == DAVINCI_MMC_DATADIR_WRITE) && (cmdtype == DAVINCI_MMC_CMDTYPE_ADTC) && (host->do_dma != 1)) davinci_fifo_data_trans(host); if (cmd->opcode == 7) { spin_lock_irqsave(&host->mmc_lock, flags); host->is_card_removed = 0; host->new_card_state = 1; host->is_card_initialized = 1; host->old_card_state = host->new_card_state; host->is_init_progress = 0; spin_unlock_irqrestore(&host->mmc_lock, flags); } if (cmd->opcode == 1 || cmd->opcode == 41) { spin_lock_irqsave(&host->mmc_lock, flags); host->is_card_initialized = 0; host->is_init_progress = 1; spin_unlock_irqrestore(&host->mmc_lock, flags); } host->is_core_command = 1; DAVINCI_MMC_WRITEL(host, ARGHL, cmd->arg); DAVINCI_MMC_WRITEL(host, CMD, cmdreg); }
static void sslsd_cmd_done(sslsd_host *host, sd_cmd_p c) { struct mmc_command *cmd; del_timer(&host->timer); cmd = host->pcmd; //printk("sslsd: cmd_done info - cmd=%d arg=%08X flag=%02X rt=%d\n", //c->cmd, c->arg, c->flag, c->rt); if (mmc_resp_type(cmd) != MMC_RSP_R2) { struct mmc_data *d; d = cmd->data; cmd->resp[0] = c->rsp; //printk("sslsd: cmd_done info - resp %08X\n", c->rsp); if (d) { struct scatterlist *sg; sd_dat_p dat; int len; int card; card = sslsd_card_type(host->mmc->card); dat = c->dat; len = dat->actual; if (!len) { if (!host->retry || (card & SSLSD_CARD_SDIO)) { goto l_done; } host->retry = 0; } /* ignore any errors & retry as long as there is progress */ c->rt = 0; sg = host->sg; len *= dat->blk; #if SD_DMA && IO_MAP==3 /* copy read data from EBM buffer */ io_rds(ebm_mem + host->sgofs, sg_virt(sg) + host->sgofs, len); #endif d->bytes_xfered += len; if (card & SSLSD_CARD_SDIO) { /* not sure if we can continue transfer from last point */ goto l_done; } #ifndef NSD_HANDLE_SG_N_ERR /* do remainder of scatter page */ if (dat->actual < dat->count) { host->sgofs += len; goto l_next; } /* go to next scatter page */ if (sg < host->sgn) { sg++; host->retry = 1; host->sg = sg; host->sgofs = 0; l_next: c->arg += (card & SSLSD_CARD_BLKADR) ? dat->actual : len; sslsd_map(sg, c, dat, host->sgofs); if (sdhc_cmd(&host->hw, c)) { goto l_done; } return; } #endif l_done: #if SD_DMA && IO_MAP==1 /* data xfer completed for scatter list - unmap it */ if (c->flag & SDCMD_F_DMA) { dma_unmap_sg(mmc_dev(host->mmc), host->sg, host->sgc, (c->flag & SDCMD_F_WR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } #endif } } if (c->rt) { printk("sslsd: cmd_done err - cmd=%d arg=%08X fl=%02X rsp=%08X rt=%d\n", c->cmd, c->arg, c->flag, c->rsp, c->rt); if (c->dat) printk("cnt=%d act=%d\n", c->dat->count, c->dat->actual); switch (c->rt) { case SDHC_RET_TOUT: case SDHC_RET_CMD_TOUT: case SDHC_RET_DAT_TOUT: cmd->error = -ETIMEDOUT; break; case SDHC_RET_DAT_LINE: case SDHC_RET_CMD_LINE: cmd->error = -EILSEQ; break; case SDHC_RET_REM: cmd->error = -ENOMEDIUM; break; default: cmd->error = -EIO; break; } } mmc_request_done(host->mmc, cmd->mrq); }
/* Send adtc command to the card */ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; int ignore_crc, resp, long_resp; int is_reading = 0; unsigned int copy_size; u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; u32 timeout; u32 val; u32 data_size = cmd->data->blksz * cmd->data->blocks; u32 log2_block_size; ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; long_resp = mmc_resp_type(cmd) & MMC_RSP_136 ? 1 : 0; dev_dbg(host->dev, "ADTC command:\n" "response: %d, ignore crc: %d\n" "data list: %u, blocksz: %u, blocks: %u, timeout: %uns %uclks, " "flags: 0x%x\n", resp, ignore_crc, cmd->data->sg_len, cmd->data->blksz, cmd->data->blocks, cmd->data->timeout_ns, cmd->data->timeout_clks, cmd->data->flags); if (cmd->data->flags & MMC_DATA_WRITE) { dev_dbg(host->dev, "Data Write\n"); copy_size = stmp3xxx_sg_dma_copy(host, data_size, 1); BUG_ON(copy_size < data_size); is_reading = 0; if (!host->regulator) __init_reg(host->dev, &host->regulator); if (host->regulator) regulator_set_current_limit(host->regulator, host->write_uA, host->write_uA); } else if (cmd->data->flags & MMC_DATA_READ) { dev_dbg(host->dev, "Data Read\n"); is_reading = 1; if (!host->regulator) __init_reg(host->dev, &host->regulator); if (host->regulator) regulator_set_current_limit(host->regulator, host->read_uA, host->read_uA); } else { dev_warn(host->dev, "Unsuspported data mode, 0x%x\n", cmd->data->flags); BUG(); } BUG_ON(cmd->data->flags & MMC_DATA_STREAM); BUG_ON((data_size % 8) > 0); dma_desc->command->cmd = BM_APBH_CHn_CMD_WAIT4ENDCMD | BM_APBH_CHn_CMD_SEMAPHORE | BM_APBH_CHn_CMD_IRQONCMPLT | BF(data_size, APBH_CHn_CMD_XFER_COUNT) | BF(3, APBH_CHn_CMD_CMDWORDS); /* when is_reading is set, DMA controller performs WRITE operation. */ dma_desc->command->cmd |= BF(is_reading ? BV_APBH_CHn_CMD_COMMAND__DMA_WRITE : BV_APBH_CHn_CMD_COMMAND__DMA_READ, APBH_CHn_CMD_COMMAND); ssp_ctrl0 = (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) | (resp ? BM_SSP_CTRL0_GET_RESP : 0) | (long_resp ? BM_SSP_CTRL0_LONG_RESP : 0) | (is_reading ? BM_SSP_CTRL0_READ : 0) | BM_SSP_CTRL0_DATA_XFER | BM_SSP_CTRL0_WAIT_FOR_IRQ | BM_SSP_CTRL0_ENABLE | BF(data_size, SSP_CTRL0_XFER_COUNT) | BF(host->bus_width_4 ? BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT : BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT, SSP_CTRL0_BUS_WIDTH); /* * We need to set the hardware register to the logarithm to base 2 of * the block size. */ log2_block_size = ilog2(cmd->data->blksz); ssp_cmd0 = BF(log2_block_size, SSP_CMD0_BLOCK_SIZE) | BF(cmd->opcode, SSP_CMD0_CMD) | BF(cmd->data->blocks - 1, SSP_CMD0_BLOCK_COUNT); if (cmd->opcode == 12) ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); dma_desc->command->pio_words[0] = ssp_ctrl0; dma_desc->command->pio_words[1] = ssp_cmd0; dma_desc->command->pio_words[2] = ssp_cmd1; /* Set the timeout count */ timeout = stmp3xxx_ns_to_ssp_ticks(host->clkrt, cmd->data->timeout_ns); val = __raw_readl(host->ssp_base + HW_SSP_TIMING); val &= ~(BM_SSP_TIMING_TIMEOUT); val |= BF(timeout, SSP_TIMING_TIMEOUT); __raw_writel(val, host->ssp_base + HW_SSP_TIMING); init_completion(&host->dma_done); stmp3xxx_dma_reset_channel(host->dmach); stmp3xxx_dma_go(host->dmach, dma_desc, 1); wait_for_completion(&host->dma_done); if (host->regulator) regulator_set_current_limit(host->regulator, 0, 0); switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: case MMC_RSP_R3: cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); break; case MMC_RSP_R2: cmd->resp[3] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); cmd->resp[2] = __raw_readl(host->ssp_base + HW_SSP_SDRESP1); cmd->resp[1] = __raw_readl(host->ssp_base + HW_SSP_SDRESP2); cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP3); break; default: dev_warn(host->dev, "Unsupported response type 0x%x\n", mmc_resp_type(cmd)); BUG(); break; } cmd->error = stmp3xxx_mmc_cmd_error(host->status); if (stmp3xxx_dma_running(host->dmach)) dev_dbg(host->dev, "DMA command not finished\n"); if (cmd->error) { dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); stmp3xxx_dma_reset_channel(host->dmach); } else { if (is_reading) cmd->data->bytes_xfered = stmp3xxx_sg_dma_copy(host, data_size, 0); else cmd->data->bytes_xfered = data_size; dev_dbg(host->dev, "Transferred %u bytes\n", cmd->data->bytes_xfered); } }
static void mxs_mmc_adtc(struct mxs_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct mmc_data *data = cmd->data; struct dma_async_tx_descriptor *desc; struct scatterlist *sgl = data->sg, *sg; unsigned int sg_len = data->sg_len; unsigned int i; unsigned short dma_data_dir, timeout; enum dma_transfer_direction slave_dirn; unsigned int data_size = 0, log2_blksz; unsigned int blocks = data->blocks; struct mxs_ssp *ssp = &host->ssp; u32 ignore_crc, get_resp, long_resp, read; u32 ctrl0, cmd0, cmd1, val; ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? 0 : BM_SSP_CTRL0_IGNORE_CRC; get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? BM_SSP_CTRL0_GET_RESP : 0; long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? BM_SSP_CTRL0_LONG_RESP : 0; if (data->flags & MMC_DATA_WRITE) { dma_data_dir = DMA_TO_DEVICE; slave_dirn = DMA_MEM_TO_DEV; read = 0; } else { dma_data_dir = DMA_FROM_DEVICE; slave_dirn = DMA_DEV_TO_MEM; read = BM_SSP_CTRL0_READ; } ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | ignore_crc | get_resp | long_resp | BM_SSP_CTRL0_DATA_XFER | read | BM_SSP_CTRL0_WAIT_FOR_IRQ | BM_SSP_CTRL0_ENABLE; cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); /* get logarithm to base 2 of block size for setting register */ log2_blksz = ilog2(data->blksz); /* * take special care of the case that data size from data->sg * is not equal to blocks x blksz */ for_each_sg(sgl, sg, sg_len, i) data_size += sg->length; if (data_size != data->blocks * data->blksz) blocks = 1; /* xfer count, block size and count need to be set differently */ if (ssp_is_old(ssp)) { ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); } else { writel(data_size, ssp->base + HW_SSP_XFER_SIZE); writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) | BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), ssp->base + HW_SSP_BLOCK_SIZE); } if ((cmd->opcode == MMC_STOP_TRANSMISSION) || (cmd->opcode == SD_IO_RW_EXTENDED)) cmd0 |= BM_SSP_CMD0_APPEND_8CYC; cmd1 = cmd->arg; if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; } /* set the timeout count */ timeout = mxs_ns_to_ssp_ticks(ssp->clk_rate, data->timeout_ns); val = readl(ssp->base + HW_SSP_TIMING(ssp)); val &= ~(BM_SSP_TIMING_TIMEOUT); val |= BF_SSP(timeout, TIMING_TIMEOUT); writel(val, ssp->base + HW_SSP_TIMING(ssp)); /* pio */ ssp->ssp_pio_words[0] = ctrl0; ssp->ssp_pio_words[1] = cmd0; ssp->ssp_pio_words[2] = cmd1; ssp->dma_dir = DMA_NONE; ssp->slave_dirn = DMA_TRANS_NONE; desc = mxs_mmc_prep_dma(host, 0); if (!desc) goto out; /* append data sg */ WARN_ON(host->data != NULL); host->data = data; ssp->dma_dir = dma_data_dir; ssp->slave_dirn = slave_dirn; desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) goto out; dmaengine_submit(desc); dma_async_issue_pending(ssp->dmach); return; out: dev_warn(mmc_dev(host->mmc), "%s: failed to prep dma\n", __func__); }
static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, struct mmc_request *mrq, struct mmc_command *cmd, u32 opc) { u32 tmp = 0; /* Response Type check */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: tmp |= CMD_SET_RTYP_NO; break; case MMC_RSP_R1: case MMC_RSP_R1B: case MMC_RSP_R3: tmp |= CMD_SET_RTYP_6B; break; case MMC_RSP_R2: tmp |= CMD_SET_RTYP_17B; break; default: pr_err(DRIVER_NAME": Not support type response.\n"); break; } switch (opc) { /* RBSY */ case MMC_SWITCH: case MMC_STOP_TRANSMISSION: case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: case MMC_GEN_CMD: tmp |= CMD_SET_RBSY; break; } /* WDAT / DATW */ if (host->data) { tmp |= CMD_SET_WDAT; switch (host->bus_width) { case MMC_BUS_WIDTH_1: tmp |= CMD_SET_DATW_1; break; case MMC_BUS_WIDTH_4: tmp |= CMD_SET_DATW_4; break; case MMC_BUS_WIDTH_8: tmp |= CMD_SET_DATW_8; break; default: pr_err(DRIVER_NAME": Not support bus width.\n"); break; } } /* DWEN */ if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) tmp |= CMD_SET_DWEN; /* CMLTE/CMD12EN */ if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, mrq->data->blocks << 16); } /* RIDXC[1:0] check bits */ if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_RIDXC_BITS; /* RCRC7C[1:0] check bits */ if (opc == MMC_SEND_OP_COND) tmp |= CMD_SET_CRC7C_BITS; /* RCRC7C[1:0] internal CRC7 */ if (opc == MMC_ALL_SEND_CID || opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_CRC7C_INTERNAL; return opc = ((opc << 24) | tmp); }
static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, struct mmc_request *mrq) { struct mmc_data *data = mrq->data; struct mmc_command *cmd = mrq->cmd; u32 opc = cmd->opcode; u32 tmp = 0; /* Response Type check */ switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: tmp |= CMD_SET_RTYP_NO; break; case MMC_RSP_R1: case MMC_RSP_R1B: case MMC_RSP_R3: tmp |= CMD_SET_RTYP_6B; break; case MMC_RSP_R2: tmp |= CMD_SET_RTYP_17B; break; default: dev_err(&host->pd->dev, "Unsupported response type.\n"); break; } switch (opc) { /* RBSY */ case MMC_SLEEP_AWAKE: case MMC_SWITCH: case MMC_STOP_TRANSMISSION: case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: tmp |= CMD_SET_RBSY; break; } /* WDAT / DATW */ if (data) { tmp |= CMD_SET_WDAT; switch (host->bus_width) { case MMC_BUS_WIDTH_1: tmp |= CMD_SET_DATW_1; break; case MMC_BUS_WIDTH_4: tmp |= CMD_SET_DATW_4; break; case MMC_BUS_WIDTH_8: tmp |= CMD_SET_DATW_8; break; default: dev_err(&host->pd->dev, "Unsupported bus width.\n"); break; } switch (host->timing) { case MMC_TIMING_UHS_DDR50: /* * MMC core will only set this timing, if the host * advertises the MMC_CAP_UHS_DDR50 capability. MMCIF * implementations with this capability, e.g. sh73a0, * will have to set it in their platform data. */ tmp |= CMD_SET_DARS; break; } } /* DWEN */ if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) tmp |= CMD_SET_DWEN; /* CMLTE/CMD12EN */ if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, data->blocks << 16); } /* RIDXC[1:0] check bits */ if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_RIDXC_BITS; /* RCRC7C[1:0] check bits */ if (opc == MMC_SEND_OP_COND) tmp |= CMD_SET_CRC7C_BITS; /* RCRC7C[1:0] internal CRC7 */ if (opc == MMC_ALL_SEND_CID || opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_CRC7C_INTERNAL; return (opc << 24) | tmp; }
static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat) { unsigned long flags; u32 imask; WARN_ON(host->cmd != NULL); host->cmd = cmd; /* Ensure, that clock are stopped else command programming and start fails */ imxmci_stop_clock(host); if (cmd->flags & MMC_RSP_BUSY) cmdat |= CMD_DAT_CONT_BUSY; switch (mmc_resp_type(cmd)) { case MMC_RSP_R1: /* short CRC, OPCODE */ case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; break; case MMC_RSP_R2: /* long 136 bit + CRC */ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; break; case MMC_RSP_R3: /* short */ cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; break; default: break; } if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) ) cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ if ( host->actual_bus_width == MMC_BUS_WIDTH_4 ) cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; MMC_CMD = cmd->opcode; MMC_ARGH = cmd->arg >> 16; MMC_ARGL = cmd->arg & 0xffff; MMC_CMD_DAT_CONT = cmdat; atomic_set(&host->stuck_timeout, 0); set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events); imask = IMXMCI_INT_MASK_DEFAULT; imask &= ~INT_MASK_END_CMD_RES; if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) { /*imask &= ~INT_MASK_BUF_READY;*/ imask &= ~INT_MASK_DATA_TRAN; if ( cmdat & CMD_DAT_CONT_WRITE ) imask &= ~INT_MASK_WRITE_OP_DONE; if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) imask &= ~INT_MASK_BUF_READY; } spin_lock_irqsave(&host->lock, flags); host->imask = imask; MMC_INT_MASK = host->imask; spin_unlock_irqrestore(&host->lock, flags); dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n", cmd->opcode, cmd->opcode, imask); imxmci_start_clock(host); }
static void sslsd_request(struct mmc_host *mmc, struct mmc_request *req) { sslsd_host *host = mmc_priv(mmc); struct mmc_command *cmd = req->cmd; sd_cmd_p c = &host->tcmd; struct mmc_data *d; int flag; unsigned long iflags; if (!sdhc_is_in(&host->hw)) { cmd->error = -ENOMEDIUM; mmc_request_done(mmc, req); return; } c->dat = 0; switch (mmc_resp_type(cmd)) { case MMC_RSP_R1: /* & R5, R6 */ flag = SDCMD_F_R1; break; case MMC_RSP_R1B: /* & R5b */ flag = SDCMD_F_R1B; break; case MMC_RSP_R2: flag = SDCMD_F_R2; c->dat = &host->tdat; c->dat->buf = (uint8_t *)cmd->resp; break; case MMC_RSP_R3: flag = SDCMD_F_R3; break; default: flag = 0; break; } c->cmd = cmd->opcode; c->arg = cmd->arg; host->pcmd = cmd; d = cmd->data; if (d) { struct scatterlist *sg; sd_dat_p dat; if (d->flags & MMC_DATA_STREAM) { /* not supported */ cmd->error = -EINVAL; mmc_request_done(mmc, req); return; } flag |= SDCMD_F_DAT; if (d->flags & MMC_DATA_WRITE) { flag |= SDCMD_F_WR; } if (d->blocks > 1) { flag |= SDCMD_F_MULTI; } #if SD_DMA if (host->hw.fdma) { flag |= SDCMD_F_DMA; } #endif dat = c->dat = &host->tdat; dat->blk = d->blksz; #if 1 c->tout = (d->timeout_ns + 1000000 - 1) / 1000000 + d->timeout_clks / (mmc->ios.clock / 1000); #endif sg = d->sg; host->sg = sg; host->sgc = d->sg_len; host->sgn = sg + d->sg_len - 1; host->sgofs = 0; #if SD_DMA && IO_MAP == 1 if (flag & SDCMD_F_DMA) { int count; count = dma_map_sg(mmc_dev(mmc), sg, d->sg_len, (flag & SDCMD_F_WR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (!count) { /* failed to map even 1 page */ cmd->error = -ENOMEM; mmc_request_done(mmc, req); return; } if (count != d->sg_len) { /* not all pages got mapped */ count = d->sg_len - count; host->sgc -= count; host->sgn -= count; } } #endif if (req->stop) { flag |= SDCMD_F_STOP; } c->flag = flag; sslsd_map(sg, c, dat, 0); host->retry = 1; } else { c->flag = flag; } //printk("sslsd: cmd info - cmd=%d arg=%08X flags=%02X\n", //cmd->opcode, cmd->arg, flag); /* 2 sec timeout */ mod_timer(&host->timer, jiffies + 2 * HZ); local_irq_save(iflags); flag = sdhc_cmd(&host->hw, c); local_irq_restore(iflags); if (flag) { sslsd_cmd_done(host, c); } }