コード例 #1
0
ファイル: at91_mci.c プロジェクト: ivucica/linux
/*
 * 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;
}
コード例 #2
0
/*
 * 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;
}