Exemplo n.º 1
0
/*
 * DMA read/write transfers with ECC support
 */
static int lpc32xx_dma_xfer(struct mtd_info *mtd, uint8_t *buf,
	int eccsubpages, int read)
{
	struct nand_chip *chip = mtd->priv;
	struct lpc32xx_nand_host *host = chip->priv;
	uint32_t config, tmpreg;
	dma_addr_t buf_phy;
	int i, timeout, dma_mapped = 0, status = 0;

	/* Map DMA buffer */
	if (likely((void *) buf < high_memory)) {
		buf_phy = dma_map_single(mtd->dev.parent, buf, mtd->writesize,
			read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
		if (unlikely(dma_mapping_error(mtd->dev.parent, buf_phy))) {
			dev_err(mtd->dev.parent,
				"Unable to map DMA buffer\n");
			dma_mapped = 0;
		} else
			dma_mapped = 1;
	}

	/* If a buffer can't be mapped, use the local buffer */
	if (!dma_mapped) {
		buf_phy = host->data_buf_dma;
		if (!read)
			memcpy(host->data_buf, buf, mtd->writesize);
	}

	if (read)
		config = DMAC_CHAN_ITC | DMAC_CHAN_IE | DMAC_CHAN_FLOW_D_P2M |
			DMAC_DEST_PERIP (0) |
			DMAC_SRC_PERIP(DMA_PERID_NAND1) | DMAC_CHAN_ENABLE;
	else
		config = DMAC_CHAN_ITC | DMAC_CHAN_IE | DMAC_CHAN_FLOW_D_M2P |
			DMAC_DEST_PERIP(DMA_PERID_NAND1) |
			DMAC_SRC_PERIP (0) | DMAC_CHAN_ENABLE;

	/* DMA mode with ECC enabled */
	tmpreg = __raw_readl(SLC_CFG(host->io_base));
	__raw_writel(SLCCFG_ECC_EN | SLCCFG_DMA_ECC | tmpreg,
		SLC_CFG(host->io_base));

	/* Clear initial ECC */
	__raw_writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));

	/* Prepare DMA descriptors */
	lpc32xx_nand_dma_configure(mtd, buf_phy, chip->ecc.steps, read);

	/* Setup DMA direction and burst mode */
	if (read)
		__raw_writel(__raw_readl(SLC_CFG(host->io_base)) |
			SLCCFG_DMA_DIR, SLC_CFG(host->io_base));
	else
		__raw_writel(__raw_readl(SLC_CFG(host->io_base)) &
			~SLCCFG_DMA_DIR, SLC_CFG(host->io_base));
	__raw_writel(__raw_readl(SLC_CFG(host->io_base)) | SLCCFG_DMA_BURST,
		SLC_CFG(host->io_base));

	/* Transfer size is data area only */
	__raw_writel(mtd->writesize, SLC_TC(host->io_base));

	/* Start transfer in the NAND controller */
	__raw_writel(__raw_readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
		SLC_CTRL(host->io_base));

	/* Start DMA to process NAND controller DMA FIFO */
	host->dmapending = 0;
	lpc32xx_dma_start_xfer(host->dmach, config);

	/*
	 * On some systems, the DMA transfer will be very fast, so there is no
	 * point in waiting for the transfer to complete using the interrupt
	 * method. It's best to just poll the transfer here to prevent several
	 * costly context changes. This is especially true for systems that
	 * use small page devices or NAND devices with very fast access.
	 */
	if (host->ncfg->polled_completion) {
		timeout = LPC32XX_DMA_SIMPLE_TIMEOUT;
		while ((timeout > 0) && lpc32xx_dma_is_active(host->dmach))
			timeout--;
		if (timeout == 0) {
			dev_err(mtd->dev.parent,
				"DMA transfer timeout error\n");
			status = -EIO;

			/* Switch to non-polled mode */
			host->ncfg->polled_completion = false;
		}
	}

	if (!host->ncfg->polled_completion) {
		/* Wait till DMA transfer is done or timeout occurs */
		wait_event_timeout(host->dma_waitq, host->dmapending,
			msecs_to_jiffies(LPC32XX_DMA_WAIT_TIMEOUT_MS));
		if (host->dma_xfer_status != 0) {
			dev_err(mtd->dev.parent, "DMA transfer error\n");
			status = -EIO;
		}
	}

	/*
	 * The DMA is finished, but the NAND controller may still have
	 * buffered data. Wait until all the data is sent.
	 */
	timeout = LPC32XX_DMA_SIMPLE_TIMEOUT;
	while ((__raw_readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO)
		&& (timeout > 0))
		timeout--;
	if (timeout == 0) {
		dev_err(mtd->dev.parent, "FIFO held data too long\n");
		status = -EIO;
	}

	/* Read last calculated ECC value */
	if (read)
		host->ecc_buf[chip->ecc.steps - 1] =
			__raw_readl(SLC_ECC(host->io_base));
	else {
		for (i = 0; i < LPC32XX_DMA_ECC_REP_READ; i++)
			host->ecc_buf[chip->ecc.steps - 1] =
				__raw_readl(SLC_ECC(host->io_base));
	}

	/*
	 * For reads, get the OOB data. For writes, the data will be written
	 * later
	 */
	if (read)
		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);

	/* Flush DMA link list */
	lpc32xx_dma_flush_llist(host->dmach);

	if (__raw_readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
		__raw_readl(SLC_TC(host->io_base))) {
		/* Something is left in the FIFO, something is wrong */
		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
		status = -EIO;
	}

	if (dma_mapped)
		dma_unmap_single(mtd->dev.parent, buf_phy, mtd->writesize,
			read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
	else if (read)
		memcpy(buf, host->data_buf, mtd->writesize);

	/* Stop DMA & HW ECC */
	__raw_writel(__raw_readl(SLC_CTRL(host->io_base)) &
		~SLCCTRL_DMA_START, SLC_CTRL(host->io_base));
	__raw_writel(tmpreg, SLC_CFG(host->io_base));

	return status;
}
Exemplo n.º 2
0
/*
 * DMA read/write transfers with ECC support
 */
static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
			int read)
{
	struct nand_chip *chip = mtd->priv;
	struct lpc32xx_nand_host *host = chip->priv;
	int i, status = 0;
	unsigned long timeout;
	int res;
	enum dma_transfer_direction dir =
		read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
	uint8_t *dma_buf;
	bool dma_mapped;

	if ((void *)buf <= high_memory) {
		dma_buf = buf;
		dma_mapped = true;
	} else {
		dma_buf = host->data_buf;
		dma_mapped = false;
		if (!read)
			memcpy(host->data_buf, buf, mtd->writesize);
	}

	if (read) {
		writel(readl(SLC_CFG(host->io_base)) |
		       SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
		       SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
	} else {
		writel((readl(SLC_CFG(host->io_base)) |
			SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
		       ~SLCCFG_DMA_DIR,
			SLC_CFG(host->io_base));
	}

	/* Clear initial ECC */
	writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));

	/* Transfer size is data area only */
	writel(mtd->writesize, SLC_TC(host->io_base));

	/* Start transfer in the NAND controller */
	writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
	       SLC_CTRL(host->io_base));

	for (i = 0; i < chip->ecc.steps; i++) {
		/* Data */
		res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
				       dma_buf + i * chip->ecc.size,
				       mtd->writesize / chip->ecc.steps, dir);
		if (res)
			return res;

		/* Always _read_ ECC */
		if (i == chip->ecc.steps - 1)
			break;
		if (!read) /* ECC availability delayed on write */
			udelay(10);
		res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
				       &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
		if (res)
			return res;
	}

	/*
	 * According to NXP, the DMA can be finished here, but the NAND
	 * controller may still have buffered data. After porting to using the
	 * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
	 * appears to be always true, according to tests. Keeping the check for
	 * safety reasons for now.
	 */
	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
		dev_warn(mtd->dev.parent, "FIFO not empty!\n");
		timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
		while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
		       time_before(jiffies, timeout))
			cpu_relax();
		if (!time_before(jiffies, timeout)) {
			dev_err(mtd->dev.parent, "FIFO held data too long\n");
			status = -EIO;
		}
	}

	/* Read last calculated ECC value */
	if (!read)
		udelay(10);
	host->ecc_buf[chip->ecc.steps - 1] =
		readl(SLC_ECC(host->io_base));

	/* Flush DMA */
	dmaengine_terminate_all(host->dma_chan);

	if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
	    readl(SLC_TC(host->io_base))) {
		/* Something is left in the FIFO, something is wrong */
		dev_err(mtd->dev.parent, "DMA FIFO failure\n");
		status = -EIO;
	}

	/* Stop DMA & HW ECC */
	writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
	       SLC_CTRL(host->io_base));
	writel(readl(SLC_CFG(host->io_base)) &
	       ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
		 SLCCFG_DMA_BURST), SLC_CFG(host->io_base));

	if (!dma_mapped && read)
		memcpy(buf, host->data_buf, mtd->writesize);

	return status;
}