/* 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; }
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; }