Exemplo n.º 1
0
/* Write to SRAM FIFO with polling SRAM fill level. */
static int qpsi_write_sram_fifo_push(struct cadence_spi_platdata *plat,
				const void *src_addr, unsigned int num_bytes)
{
	const void *reg_base = plat->regbase;
	void *dest_addr = plat->ahbbase;
	unsigned int retry = CQSPI_REG_RETRY;
	unsigned int sram_level;
	unsigned int wr_bytes;
	unsigned char *src = (unsigned char *)src_addr;
	int remaining = num_bytes;
	unsigned int page_size = plat->page_size;
	unsigned int sram_threshold_words = CQSPI_REG_SRAM_THRESHOLD_WORDS;

	while (remaining > 0) {
		retry = CQSPI_REG_RETRY;
		while (retry--) {
			sram_level = CQSPI_GET_WR_SRAM_LEVEL(reg_base);
			if (sram_level <= sram_threshold_words)
				break;
		}
		if (!retry) {
			printf("QSPI: SRAM fill level (0x%08x) not hit lower expected level (0x%08x)",
			       sram_level, sram_threshold_words);
			return -1;
		}
		/* Write a page or remaining bytes. */
		wr_bytes = (remaining > page_size) ?
					page_size : remaining;

		cadence_qspi_apb_write_fifo_data(dest_addr, src, wr_bytes);
		src += wr_bytes;
		remaining -= wr_bytes;
	}

	return 0;
}
Exemplo n.º 2
0
static int cadence_qspi_apb_indirect_write_execute(
	struct struct_cqspi *cadence_qspi, unsigned txlen,
	const unsigned char *txbuf)
{
	int ret;
	unsigned int timeout;
	unsigned int reg = 0;
	unsigned int *irq_status = &(cadence_qspi->irq_status);
	void *reg_base = cadence_qspi->iobase;
	void *ahb_base = cadence_qspi->qspi_ahb_virt;
	struct platform_device *pdev = cadence_qspi->pdev;
	struct cqspi_platform_data *pdata = pdev->dev.platform_data;
	struct cqspi_flash_pdata *f_pdata =
			&(pdata->f_pdata[cadence_qspi->current_cs]);
	unsigned int page_size = f_pdata->page_size;
	int remaining = (int)txlen;
	unsigned int write_bytes;

	pr_debug("%s txlen %d txbuf %p\n", __func__, txlen, txbuf);
	hex_dump((unsigned int)txbuf, txbuf, txlen);
	CQSPI_WRITEL(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);

	CQSPI_WRITEL(CQSPI_REG_SRAM_THRESHOLD_BYTES, reg_base +
			CQSPI_REG_INDIRECTWRWATERMARK);

	CQSPI_WRITEL(CQSPI_REG_SRAM_PARTITION_WR,
			reg_base + CQSPI_REG_SRAMPARTITION);

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

	CQSPI_WRITEL(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK);

	CQSPI_WRITEL(CQSPI_REG_INDIRECTWR_START_MASK,
			reg_base + CQSPI_REG_INDIRECTWR);

	/* Write a page or remaining bytes. */
	write_bytes = remaining > page_size ? page_size : remaining;
	/* Fill up the data at the begining */
	cadence_qspi_apb_write_fifo_data(ahb_base, txbuf, write_bytes);
	txbuf += write_bytes;
	remaining -= write_bytes;

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

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

		if (*irq_status & (CQSPI_REG_IRQ_UNDERFLOW |
			CQSPI_REG_IRQ_IND_COMP | CQSPI_REG_IRQ_WATERMARK)){
			/* Calculate number of bytes to write. */
			write_bytes = remaining > page_size ?
				page_size : remaining;

			cadence_qspi_apb_write_fifo_data(ahb_base, txbuf,
				write_bytes);
			txbuf  += write_bytes;
			remaining -= write_bytes;
		}
	}

	/* 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_INDIRECTWR);
		if (reg & CQSPI_REG_INDIRECTWR_DONE_MASK)
			break;
	}

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

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

	/* Clear indirect completion status */
	CQSPI_WRITEL(CQSPI_REG_INDIRECTWR_DONE_MASK,
		reg_base + CQSPI_REG_INDIRECTWR);
	return 0;

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

	/* Cancel the indirect write */
	CQSPI_WRITEL(CQSPI_REG_INDIRECTWR_CANCEL_MASK,
		reg_base + CQSPI_REG_INDIRECTWR);
	return ret;
}