static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv, u32 gen_fifo_cmd, u32 *buf) { u32 len; u32 actuallen = priv->len; u32 config_reg, ier, isr; u32 timeout = GQSPI_TIMEOUT; struct zynqmp_qspi_regs *regs = priv->regs; u32 last_bits; u32 *traverse = buf; while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); /* If exponent bit is set, reset immediate to be 2^len */ if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) priv->bytes_to_receive = (1 << len); else priv->bytes_to_receive = len; zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); /* Manual start */ config_reg = readl(®s->confr); config_reg |= GQSPI_STRT_GEN_FIFO; writel(config_reg, ®s->confr); /* Enable RX interrupts for IO mode */ ier = readl(®s->ier); ier |= GQSPI_IXR_ALL_MASK; writel(ier, ®s->ier); while (priv->bytes_to_receive && timeout) { isr = readl(®s->isr); if (isr & GQSPI_IXR_RXNEMTY_MASK) { if (priv->bytes_to_receive >= 4) { *traverse = readl(®s->drxr); traverse++; priv->bytes_to_receive -= 4; } else { last_bits = readl(®s->drxr); memcpy(traverse, &last_bits, priv->bytes_to_receive); priv->bytes_to_receive = 0; } timeout = GQSPI_TIMEOUT; } else { udelay(1); timeout--; } } debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n", (unsigned long)buf, (unsigned long)priv->rx_buf, *buf, actuallen); if (!timeout) { printf("IO timeout: %d\n", readl(®s->isr)); return -1; } } return 0; }
static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, u32 gen_fifo_cmd, u32 *buf) { u32 addr; u32 size, len; u32 actuallen = priv->len; int ret = 0; struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs; writel((unsigned long)buf, &dma_regs->dmadst); writel(roundup(priv->len, ARCH_DMA_MINALIGN), &dma_regs->dmasize); writel(GQSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); addr = (unsigned long)buf; size = roundup(priv->len, ARCH_DMA_MINALIGN); flush_dcache_range(addr, addr + size); while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); if (!(gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) && (len % ARCH_DMA_MINALIGN)) { gen_fifo_cmd &= ~GENMASK(7, 0); gen_fifo_cmd |= roundup(len, ARCH_DMA_MINALIGN); } zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); } ret = wait_for_bit_le32(&dma_regs->dmaisr, GQSPI_DMA_DST_I_STS_DONE, 1, GQSPI_TIMEOUT, 1); if (ret) { printf("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr)); return -ETIMEDOUT; } writel(GQSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr); debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n", (unsigned long)buf, (unsigned long)priv->rx_buf, *buf, actuallen); if (buf != priv->rx_buf) memcpy(priv->rx_buf, buf, actuallen); return 0; }
static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) { u32 gen_fifo_cmd; u32 len; int ret = 0; struct zynqmp_qspi_regs *regs = priv->regs; gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_TX | ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; if (priv->stripe) gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; if (last_cmd == QUAD_PAGE_PROGRAM_CMD) gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_QSPI; else gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); writel(gen_fifo_cmd, ®s->genfifo); debug("GFIFO_CMD_TX:0x%x\n", gen_fifo_cmd); if (gen_fifo_cmd & ZYNQMP_QSPI_GFIFO_EXP_MASK) ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len); else ret = zynqmp_qspi_fill_tx_fifo(priv, len); if (ret) return ret; } return ret; }
static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) { u32 gen_fifo_cmd; u32 *buf; u32 addr; u32 size, len; u32 timeout = 10000000; u32 actuallen = priv->len; struct zynqmp_qspi_regs *regs = priv->regs; struct zynqmp_qspi_dma_regs *dma_regs = priv->dma_regs; gen_fifo_cmd = zynqmp_qspi_bus_select(priv); gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_RX | ZYNQMP_QSPI_GFIFO_DATA_XFR_MASK; if (last_cmd == QUAD_OUT_READ_CMD) gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_QSPI; else gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI; if (priv->stripe) gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_STRIPE_MASK; if (!((u32)priv->rx_buf & 0x3) && !(actuallen % 4)) { buf = (u32 *)priv->rx_buf; } else { ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len, 4)); buf = (u32 *)tmp; } writel((u32)buf, &dma_regs->dmadst); writel(roundup(priv->len, 4), &dma_regs->dmasize); writel(ZYNQMP_QSPI_DMA_DST_I_STS_MASK, &dma_regs->dmaier); addr = (u32)buf; size = roundup(priv->len, ARCH_DMA_MINALIGN); flush_dcache_range(addr, addr+size); while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); if (!(gen_fifo_cmd & ZYNQMP_QSPI_GFIFO_EXP_MASK) && (len % 4)) { gen_fifo_cmd &= ~(0xFF); gen_fifo_cmd |= (len/4 + 1) * 4; } writel(gen_fifo_cmd, ®s->genfifo); debug("GFIFO_CMD_RX:0x%x\n", gen_fifo_cmd); } while (timeout) { if (readl(&dma_regs->dmaisr) & ZYNQMP_QSPI_DMA_DST_I_STS_DONE) { writel(ZYNQMP_QSPI_DMA_DST_I_STS_DONE, &dma_regs->dmaisr); break; } timeout--; } debug("buf:0x%lx, rxbuf:0x%lx, *buf:0x%x len: 0x%x\n", (unsigned long)buf, (unsigned long)priv->rx_buf, *buf, actuallen); if (!timeout) { debug("DMA Timeout:0x%x\n", readl(&dma_regs->dmaisr)); return -1; } if (buf != priv->rx_buf) memcpy(priv->rx_buf, buf, actuallen); return 0; }