Esempio n. 1
0
/* 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;
}
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;
}