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