/*
 * 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;
}
Beispiel #2
0
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
	}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
}