/* * 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 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 s3c_sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct s3c_sdi_host *host = mmc_priv(mmc); u32 sdi_carg, sdi_ccon, sdi_timer, sdi_fsta; u32 sdi_bsize, sdi_dcon = 0, sdi_imsk; u32 dma_dir = 0; unsigned long complete_timeout = msecs_to_jiffies( 1000 ); // 1000 msec timeout on wait for command completion WARN_ON(host->mrq != NULL); DBG("#############request: [CMD] opcode:0x%02x arg:0x%08x flags:%x retries:%u\n", mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags, mrq->cmd->retries); host->mrq = mrq; sdi_ccon = mrq->cmd->opcode & S3C_SDICCON_INDEX; sdi_ccon|= (S3C_SDICCON_SENDERHOST | S3C_SDICCON_CMDSTART); #ifdef CONFIG_S3CMCI_DEBUG { cmd_rec[cmd_idx] = mrq->cmd->opcode; cmd_idx++; cmd_idx %= 40; } #endif sdi_carg = mrq->cmd->arg; /* XXX: Timer value ?! */ /* If the workaround for read is enabled, change the timer value. */ if( host->ena_2410_workaround ) sdi_timer=0xFFFF; else sdi_timer= 0x7fffff; sdi_bsize= 0; /* enable interrupts for transmission errors */ sdi_imsk = (S3C_SDIIMSK_RESPONSEND | S3C_SDIIMSK_CRCSTATUS); host->complete_what = COMPLETION_CMDSENT; if (RSP_TYPE(mmc_resp_type(mrq->cmd))) { host->complete_what = COMPLETION_RSPFIN; sdi_ccon |= S3C_SDICCON_WAITRSP; sdi_imsk |= S3C_SDIIMSK_CMDTIMEOUT; } else { /* We need the CMDSENT-Interrupt only if we want are not waiting * for a response */ sdi_imsk |= S3C_SDIIMSK_CMDSENT; } if (mrq->cmd->flags & MMC_RSP_136) { sdi_ccon|= S3C_SDICCON_LONGRSP; } if (mrq->cmd->flags & MMC_RSP_CRC) { sdi_imsk |= S3C_SDIIMSK_RESPONSECRC; } if (mrq->data) { host->complete_what = COMPLETION_XFERFINISH_RSPFIN; sdi_ccon|= S3C_SDICCON_WITHDATA; sdi_bsize = mrq->data->blksz; sdi_dcon = (mrq->data->blocks & S3C_SDIDCON_BLKNUM_MASK); sdi_dcon |= S3C_SDIDCON_DMAEN; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_WORDTX; if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) { sdi_dcon |= S3C_SDIDCON_WIDEBUS; } sdi_imsk |= 0xFFFFFFE0; DBG(PFX "request: [DAT] bsize:%u blocks:%u bytes:%u\n", sdi_bsize, mrq->data->blocks, mrq->data->blocks * sdi_bsize); if (!(mrq->data->flags & MMC_DATA_STREAM)) { sdi_dcon |= S3C_SDIDCON_BLOCKMODE; } if (mrq->data->flags & MMC_DATA_WRITE) { sdi_dcon |= S3C_SDIDCON_TXAFTERRESP; sdi_dcon |= S3C_SDIDCON_XFER_TX; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_DSTART; s3c_sdi_dma_setup(host, DMAP_WRITE); dma_dir = DMA_TO_DEVICE; } else { sdi_dcon |= S3C_SDIDCON_RXAFTERCMD; sdi_dcon |= S3C_SDIDCON_XFER_RX; if( !host->ena_2410_workaround ) sdi_dcon |= S3C_SDIDCON_DSTART; s3c_sdi_dma_setup(host, DMAP_READ); dma_dir = DMA_FROM_DEVICE; } /* Clear FAIL bits also for the fifo. */ sdi_fsta = S3C_SDIFSTA_FRST | S3C_SDIFSTA_FIFOFAIL; __raw_writel(sdi_fsta,host->base + S3C_SDIFSTA); /* start DMA */ dma_map_sg(mmc_dev(mmc), mrq->data->sg, mrq->data->sg_len, dma_dir); #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_enqueue(host->dma,host->subchannel,(void *) host, sg_dma_address(mrq->data->sg), (mrq->data->blocks * mrq->data->blksz) ); #else s3c_dma_enqueue(host->dma, (void *) host, sg_dma_address(mrq->data->sg), (mrq->data->blocks * mrq->data->blksz) ); #endif /* Check if we should enable the workaround for timeouts in the 2410 soc. */ /* Since we want to go as fast as possible, don't use the maximum divider.*/ /* dividing by 90 will give a clock of roughly 553MHz. This should be safe*/ /* enough. */ host->prescaler=readl( host->base + S3C_SDIPRE ); if( host->ena_2410_workaround && (mrq->data->flags & MMC_DATA_READ) ) writel( (clk_get_rate( host->clk )/533000), host->base + S3C_SDIPRE ); } host->mrq = mrq; init_completion(&host->complete_request); init_completion(&host->complete_dma); /* Clear command and data status registers */ writel(0xFFFFFFFF, host->base + S3C_SDICSTA); writel(0xFFFFFFFF, host->base + S3C_SDIDSTA); /* Setup SDI controller */ writel(sdi_bsize,host->base + S3C_SDIBSIZE); writel(sdi_timer,host->base + S3C_SDITIMER); writel(sdi_imsk,host->base + S3C_SDIIMSK); /* Setup SDI command argument and data control */ writel(sdi_carg, host->base + S3C_SDICARG); writel(sdi_dcon, host->base + S3C_SDIDCON); /* This initiates transfer */ writel(sdi_ccon, host->base + S3C_SDICCON); /* Workaround for S3C2410. When the receive transfer has started we can write the */ /* original prescaler back to transfer at maximum speed. Talk about a dirty hack...*/ if( host->ena_2410_workaround && (mrq->data != NULL) && (mrq->data->flags & MMC_DATA_READ) ) { /* Start polling if the receive transfer has started.... */ while( ((readl( host->base + S3C_SDIFSTA ) & 0x7F) == 0) && ((readl( host->base + S3C_SDIDSTA ) & 0x30) == 0) ) { /* Ensure that if an error occurs, we can still exit. */ if( readl( host->base + S3C_SDIDSTA ) & (S3C_SDIDSTA_FIFOFAIL | S3C_SDIDSTA_CRCFAIL | S3C_SDIDSTA_RXCRCFAIL | S3C_SDIDSTA_DATATIMEOUT | S3C_SDIDSTA_SBITERR) ) break; } writel( host->prescaler, host->base + S3C_SDIPRE ); } /* this wait is very important to sd/mmc run correctly. * Without this blocking code, operation sequence may be crashed. * by scsuh. */ /* Wait for transfer to complete */ wait_for_completion_timeout(&host->complete_request, complete_timeout); if (mrq->data && (host->mrq->data->error == MMC_ERR_NONE)) { if (wait_for_completion_timeout(&host->complete_dma, complete_timeout) == 0) { #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_ctrl(host->dma,host->subchannel, S3C_DMAOP_FLUSH); #else s3c_dma_ctrl(host->dma, S3C_DMAOP_FLUSH); #endif } DBG("[DAT] DMA complete.\n"); sdi_fsta = readl(host->base + S3C_SDIFSTA); writel(sdi_fsta,host->base + S3C_SDIFSTA); } /* Cleanup controller */ writel(0, host->base + S3C_SDICARG); writel(0, host->base + S3C_SDIDCON); writel(0, host->base + S3C_SDICCON); writel(0, host->base + S3C_SDIIMSK); /* Read response */ mrq->cmd->resp[0] = readl(host->base + S3C_SDIRSP0); mrq->cmd->resp[1] = readl(host->base + S3C_SDIRSP1); mrq->cmd->resp[2] = readl(host->base + S3C_SDIRSP2); mrq->cmd->resp[3] = readl(host->base + S3C_SDIRSP3); host->mrq = NULL; DBG(PFX "request done.\n"); if (mrq->data) { dma_unmap_sg(mmc_dev(mmc), mrq->data->sg, mrq->data->sg_len, dma_dir); /* Calculate the about of bytes transfer, but only if there was * no error */ if (mrq->data->error == MMC_ERR_NONE) mrq->data->bytes_xfered = (mrq->data->blocks * mrq->data->blksz); else mrq->data->bytes_xfered = 0; /* If we had an error while transferring data we flush the * DMA channel to clear out any garbage */ if (mrq->data->error != MMC_ERR_NONE) { #ifdef CONFIG_ARCH_MDIRAC3 s3c_dma_ctrl(host->dma,host->subchannel, S3C_DMAOP_FLUSH); #else s3c_dma_ctrl(host->dma, S3C_DMAOP_FLUSH); #endif DBG(PFX "flushing DMA.\n"); } /* Issue stop command */ if (mrq->data->stop) mmc_wait_for_cmd(mmc, mrq->data->stop, 3); } mrq->done(mrq); }