Exemple #1
0
static int
dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
{
	struct dwmci_host *host = to_dwmci_host(mci);
	int flags = 0;
	uint32_t mask;
	uint32_t ctrl;
	uint64_t start;
	int ret;
	unsigned int num_bytes = 0;

	start = get_time_ns();
	while (1) {
		if (!(dwmci_readl(host, DWMCI_STATUS) & DWMCI_STATUS_BUSY))
			break;

		if (is_timeout(start, 100 * MSECOND)) {
			dev_dbg(host->dev, "Timeout on data busy\n");
			return -ETIMEDOUT;
		}
	}

	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);

	if (data) {
		num_bytes = data->blocks * data->blocksize;

		if (data->flags & MMC_DATA_WRITE)
			dma_sync_single_for_device((unsigned long)data->src,
						   num_bytes, DMA_TO_DEVICE);
		else
			dma_sync_single_for_device((unsigned long)data->dest,
						   num_bytes, DMA_FROM_DEVICE);

		ret = dwmci_prepare_data(host, data);
		if (ret)
			return ret;
	}

	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);

	if (data)
		flags = dwmci_set_transfer_mode(host, data);

	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
		return -EINVAL;

	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
		flags |= DWMCI_CMD_ABORT_STOP;
	else
		flags |= DWMCI_CMD_PRV_DAT_WAIT;

	if (cmd->resp_type & MMC_RSP_PRESENT) {
		flags |= DWMCI_CMD_RESP_EXP;
		if (cmd->resp_type & MMC_RSP_136)
			flags |= DWMCI_CMD_RESP_LENGTH;
	}

	if (cmd->resp_type & MMC_RSP_CRC)
		flags |= DWMCI_CMD_CHECK_CRC;

	flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG);

	dev_dbg(host->dev, "Sending CMD%d\n", cmd->cmdidx);

	dwmci_writel(host, DWMCI_CMD, flags);

	start = get_time_ns();
	while (1) {
		mask = dwmci_readl(host, DWMCI_RINTSTS);
		if (mask & DWMCI_INTMSK_CDONE) {
			if (!data)
				dwmci_writel(host, DWMCI_RINTSTS, mask);
			break;
		}
		if (is_timeout(start, 100 * MSECOND)) {
			dev_dbg(host->dev, "Send command timeout..\n");
			return -ETIMEDOUT;
		}
	}

	if (mask & DWMCI_INTMSK_RTO) {
		dev_dbg(host->dev, "Response Timeout..\n");
		return -ETIMEDOUT;
	} else if (mask & DWMCI_INTMSK_RE) {
		dev_dbg(host->dev, "Response Error..\n");
		return -EIO;
	}

	if (cmd->resp_type & MMC_RSP_PRESENT) {
		if (cmd->resp_type & MMC_RSP_136) {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP3);
			cmd->response[1] = dwmci_readl(host, DWMCI_RESP2);
			cmd->response[2] = dwmci_readl(host, DWMCI_RESP1);
			cmd->response[3] = dwmci_readl(host, DWMCI_RESP0);
		} else {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP0);
		}
	}

	if (data) {
		start = get_time_ns();
		do {
			mask = dwmci_readl(host, DWMCI_RINTSTS);

			if (mask & (DWMCI_DATA_ERR)) {
				dev_dbg(host->dev, "DATA ERROR!\n");
				return -EIO;
			}

			if (!dwmci_use_pio(host) && (mask & DWMCI_DATA_TOUT)) {
				dev_dbg(host->dev, "DATA TIMEOUT!\n");
				return -EIO;
			}

			if (is_timeout(start, SECOND * 10)) {
				dev_dbg(host->dev, "Data timeout\n");
				return -ETIMEDOUT;
			}

			if (dwmci_use_pio(host) && (mask & DWMCI_INTMSK_RXDR)) {
				dwmci_read_data_pio(host, data);
				mask = dwmci_readl(host, DWMCI_RINTSTS);
			}
			if (dwmci_use_pio(host) && (mask & DWMCI_INTMSK_TXDR)) {
				dwmci_write_data_pio(host, data);
				mask = dwmci_readl(host, DWMCI_RINTSTS);
			}
		} while (!(mask & DWMCI_INTMSK_DTO));

		dwmci_writel(host, DWMCI_RINTSTS, mask);

		if (!dwmci_use_pio(host)) {
			ctrl = dwmci_readl(host, DWMCI_CTRL);
			ctrl &= ~(DWMCI_DMA_EN);
			dwmci_writel(host, DWMCI_CTRL, ctrl);

			if (data->flags & MMC_DATA_WRITE)
				dma_sync_single_for_cpu((unsigned long)data->src,
							num_bytes, DMA_TO_DEVICE);
			else
				dma_sync_single_for_cpu((unsigned long)data->dest,
							num_bytes, DMA_FROM_DEVICE);
		}
	}

	udelay(100);

	return 0;
}
Exemple #2
0
static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
		struct mmc_data *data)
{
	struct dwmci_host *host = (struct dwmci_host *)mmc->priv;
	int flags = 0, i;
	unsigned int timeout = 100000;
	u32 retry = 10000;
	u32 mask, ctrl;

	while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
		if (timeout == 0) {
			printf("Timeout on data busy\n");
			return TIMEOUT;
		}
		timeout--;
	}

	dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);

	if (data)
		dwmci_prepare_data(host, data);


	dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg);

	if (data)
		flags = dwmci_set_transfer_mode(host, data);

	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
		return -1;

	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
		flags |= DWMCI_CMD_ABORT_STOP;
	else
		flags |= DWMCI_CMD_PRV_DAT_WAIT;

	if (cmd->resp_type & MMC_RSP_PRESENT) {
		flags |= DWMCI_CMD_RESP_EXP;
		if (cmd->resp_type & MMC_RSP_136)
			flags |= DWMCI_CMD_RESP_LENGTH;
	}

	if (cmd->resp_type & MMC_RSP_CRC)
		flags |= DWMCI_CMD_CHECK_CRC;

	flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG);

	debug("Sending CMD%d\n",cmd->cmdidx);

	dwmci_writel(host, DWMCI_CMD, flags);

	for (i = 0; i < retry; i++) {
		mask = dwmci_readl(host, DWMCI_RINTSTS);
		if (mask & DWMCI_INTMSK_CDONE) {
			if (!data)
				dwmci_writel(host, DWMCI_RINTSTS, mask);
			break;
		}
	}

	if (i == retry)
		return TIMEOUT;

	if (mask & DWMCI_INTMSK_RTO) {
		debug("Response Timeout..\n");
		return TIMEOUT;
	} else if (mask & DWMCI_INTMSK_RE) {
		debug("Response Error..\n");
		return -1;
	}


	if (cmd->resp_type & MMC_RSP_PRESENT) {
		if (cmd->resp_type & MMC_RSP_136) {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP3);
			cmd->response[1] = dwmci_readl(host, DWMCI_RESP2);
			cmd->response[2] = dwmci_readl(host, DWMCI_RESP1);
			cmd->response[3] = dwmci_readl(host, DWMCI_RESP0);
		} else {
			cmd->response[0] = dwmci_readl(host, DWMCI_RESP0);
		}
	}

	if (data) {
		do {
			mask = dwmci_readl(host, DWMCI_RINTSTS);
			if (mask & (DWMCI_DATA_ERR | DWMCI_DATA_TOUT)) {
				debug("DATA ERROR!\n");
				return -1;
			}
		} while (!(mask & DWMCI_INTMSK_DTO));

		dwmci_writel(host, DWMCI_RINTSTS, mask);

		ctrl = dwmci_readl(host, DWMCI_CTRL);
		ctrl &= ~(DWMCI_DMA_EN);
		dwmci_writel(host, DWMCI_CTRL, ctrl);
	}

	udelay(100);

	return 0;
}