コード例 #1
0
ファイル: cadence_qspi_apb.c プロジェクト: CreatorDev/u-boot
/* Read from SRAM FIFO with polling SRAM fill level. */
static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr,
			const void *src_addr,  unsigned int num_bytes)
{
	unsigned int remaining = num_bytes;
	unsigned int retry;
	unsigned int sram_level = 0;
	unsigned char *dest = (unsigned char *)dest_addr;

	while (remaining > 0) {
		retry = CQSPI_REG_RETRY;
		while (retry--) {
			sram_level = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
			if (sram_level)
				break;
			udelay(1);
		}

		if (!retry) {
			printf("QSPI: No receive data after polling for %d times\n",
			       CQSPI_REG_RETRY);
			return -1;
		}

		sram_level *= CQSPI_FIFO_WIDTH;
		sram_level = sram_level > remaining ? remaining : sram_level;

		/* Read data from FIFO. */
		cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level);
		dest += sram_level;
		remaining -= sram_level;
		udelay(1);
	}
	return 0;
}
コード例 #2
0
static int cadence_qspi_apb_indirect_read_execute(
	struct struct_cqspi *cadence_qspi, unsigned rxlen,
	unsigned char *rxbuf)
{
	unsigned int reg = 0;
	unsigned int timeout;
	unsigned int watermark = CQSPI_REG_SRAM_THRESHOLD_BYTES;
	unsigned int *irq_status = &(cadence_qspi->irq_status);
	struct platform_device *pdev = cadence_qspi->pdev;
	struct cqspi_platform_data *pdata = pdev->dev.platform_data;
	void *reg_base = cadence_qspi->iobase;
	void *ahb_base = cadence_qspi->qspi_ahb_virt;
	int remaining = (int)rxlen;
	int ret = 0;

#ifdef DEBUG
	unsigned char *saverxbuf = rxbuf;
	unsigned saverxlen = rxlen;
#endif /* #ifdef DEBUG */

	pr_debug("%s rxlen %d rxbuf %p\n", __func__, rxlen, rxbuf);
	if (remaining < watermark)
		watermark = remaining;

	CQSPI_WRITEL(watermark, reg_base + CQSPI_REG_INDIRECTRDWATERMARK);
	CQSPI_WRITEL(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
	CQSPI_WRITEL(pdata->fifo_depth - CQSPI_REG_SRAM_RESV_WORDS,
		reg_base + CQSPI_REG_SRAMPARTITION);

	/* Clear all interrupts. */
	CQSPI_WRITEL(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);

	CQSPI_WRITEL(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);

	CQSPI_WRITEL(CQSPI_REG_INDIRECTRD_START_MASK,
			reg_base + CQSPI_REG_INDIRECTRD);

	while (remaining > 0) {
		ret = wait_event_interruptible_timeout(cadence_qspi->waitqueue,
			*irq_status, CQSPI_TIMEOUT_MS);
		if (!ret) {
			pr_err("QSPI: Indirect read timeout\n");
			ret = -ETIMEDOUT;
			goto failrd;
		}

		if (*irq_status & CQSPI_IRQ_STATUS_ERR) {
			/* Error occurred */
			pr_err("QSPI: Indirect read error IRQ status 0x%08x\n",
				*irq_status);
			ret = -EPERM;
			goto failrd;
		}

		if (*irq_status & (CQSPI_REG_IRQ_IND_RD_OVERFLOW |
			CQSPI_REG_IRQ_IND_COMP | CQSPI_REG_IRQ_WATERMARK)) {

			reg = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
			/* convert to bytes */
			reg *= CQSPI_FIFO_WIDTH;
			reg = reg > remaining ? remaining : reg;
			/* Read data from FIFO. */
			cadence_qspi_apb_read_fifo_data(rxbuf, ahb_base, reg);
			rxbuf += reg;
			remaining -= reg;
		}
	}

	/* Check indirect done status */
	timeout = cadence_qspi_init_timeout(CQSPI_TIMEOUT_MS);
	while (cadence_qspi_check_timeout(timeout)) {
		reg = CQSPI_READL(reg_base + CQSPI_REG_INDIRECTRD);
		if (reg & CQSPI_REG_INDIRECTRD_DONE_MASK)
			break;
	}

	if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) {
		pr_err("QSPI : Indirect read completion status error with "
			"reg 0x%08x\n", reg);
		ret = -ETIMEDOUT;
		goto failrd;
	}

	/* Disable interrupt */
	CQSPI_WRITEL(0, reg_base + CQSPI_REG_IRQMASK);

	/* Clear indirect completion status */
	CQSPI_WRITEL(CQSPI_REG_INDIRECTRD_DONE_MASK,
		reg_base + CQSPI_REG_INDIRECTRD);
	hex_dump((unsigned int)saverxbuf, saverxbuf, saverxlen);
	return 0;

failrd:
	/* Disable interrupt */
	CQSPI_WRITEL(0, reg_base + CQSPI_REG_IRQMASK);

	/* Cancel the indirect read */
	CQSPI_WRITEL(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
			reg_base + CQSPI_REG_INDIRECTRD);
	return ret;
}
コード例 #3
0
ファイル: cadence-quadspi.c プロジェクト: jiangxilong/barebox
static int cqspi_indirect_read_execute(struct spi_nor *nor,
				       u8 *rxbuf, unsigned n_rx)
{
	int ret = 0;
	unsigned int reg = 0;
	unsigned int bytes_to_read = 0;
	unsigned int watermark;
	struct cqspi_st *cqspi = nor->priv;
	void __iomem *reg_base = cqspi->iobase;
	void __iomem *ahb_base = cqspi->ahb_base;
	int remaining = (int)n_rx;

	watermark = cqspi->fifo_depth * CQSPI_FIFO_WIDTH / 2;
	writel(watermark, reg_base + CQSPI_REG_INDIRECTRDWATERMARK);
	writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);

	/* Clear all interrupts. */
	writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);

	cqspi->irq_mask = CQSPI_IRQ_MASK_RD;
	writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK);

	writel(CQSPI_REG_INDIRECTRD_START_MASK,
		reg_base + CQSPI_REG_INDIRECTRD);

	while (remaining > 0) {
		unsigned int irq_status;

		ret = wait_on_timeout(CQSPI_READ_TIMEOUT_MS,
			readl(reg_base + CQSPI_REG_IRQSTATUS) & cqspi->irq_mask);

		irq_status = readl(reg_base + CQSPI_REG_IRQSTATUS);
		bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);

		/* Clear all interrupts. */
		writel(irq_status, reg_base + CQSPI_REG_IRQSTATUS);

		if (!ret && bytes_to_read == 0) {
			dev_err(nor->dev, "Indirect read timeout, no bytes\n");
			ret = -ETIMEDOUT;
			goto failrd;
		}

		while (bytes_to_read != 0) {
			bytes_to_read *= CQSPI_FIFO_WIDTH;
			bytes_to_read = bytes_to_read > remaining
					? remaining : bytes_to_read;
			cqspi_fifo_read(rxbuf, ahb_base, bytes_to_read);
			rxbuf += bytes_to_read;
			remaining -= bytes_to_read;
			bytes_to_read = CQSPI_GET_RD_SRAM_LEVEL(reg_base);
		}
	}

	/* Check indirect done status */
	if (wait_on_timeout(CQSPI_TIMEOUT_MS,
		readl(reg_base + CQSPI_REG_INDIRECTRD) &
			CQSPI_REG_INDIRECTRD_DONE_MASK)) {
		dev_err(nor->dev,
			"Indirect read completion error 0x%08x\n", reg);
		ret = -ETIMEDOUT;
		goto failrd;
	}

	/* Disable interrupt */
	writel(0, reg_base + CQSPI_REG_IRQMASK);

	/* Clear indirect completion status */
	writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD);

	return 0;

 failrd:
	/* Disable interrupt */
	writel(0, reg_base + CQSPI_REG_IRQMASK);

	/* Cancel the indirect read */
	writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
	       reg_base + CQSPI_REG_INDIRECTRD);
	return ret;
}