예제 #1
0
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
{
	u8 command = 1;
	u32 gen_fifo_cmd;
	u32 bytecount = 0;
	struct zynqmp_qspi_regs *regs = priv->regs;

	while (priv->len) {
		gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
		gen_fifo_cmd |= ZYNQMP_QSPI_GFIFO_TX;

		if (command) {
			command = 0;
			last_cmd = *(u8 *)priv->tx_buf;
		}

		gen_fifo_cmd |= ZYNQMP_QSPI_SPI_MODE_SPI;
		gen_fifo_cmd |= *(u8 *)priv->tx_buf;
		bytecount++;
		priv->len--;
		priv->tx_buf = (u8 *)priv->tx_buf + 1;

		debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);

		writel(gen_fifo_cmd, &regs->genfifo);
	}
}
예제 #2
0
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
{
	u8 command = 1;
	u32 gen_fifo_cmd;
	u32 bytecount = 0;

	if (priv->dummy_bytes)
		priv->len -= priv->dummy_bytes;

	while (priv->len) {
		gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
		gen_fifo_cmd |= GQSPI_GFIFO_TX;

		if (command) {
			command = 0;
			last_cmd = *(u8 *)priv->tx_buf;
		}

		gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
		gen_fifo_cmd |= *(u8 *)priv->tx_buf;
		bytecount++;
		priv->len--;
		priv->tx_buf = (u8 *)priv->tx_buf + 1;

		debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);

		zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
	}

	if (priv->dummy_bytes) {
		gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
		gen_fifo_cmd &= ~(GQSPI_GFIFO_TX | GQSPI_GFIFO_RX);
		if (priv->tx_rx_mode & SPI_RX_QUAD)
			gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI;
		else if (priv->tx_rx_mode & SPI_RX_DUAL)
			gen_fifo_cmd |= GQSPI_SPI_MODE_DUAL_SPI;
		else
			gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
		gen_fifo_cmd |= GQSPI_GFIFO_DATA_XFR_MASK;
		gen_fifo_cmd |= (priv->dummy_bytes * 8);
		zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
	}
}
예제 #3
0
static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
{
	u32 gen_fifo_cmd;
	u32 *buf;
	u32 actuallen = priv->len;

	gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
	gen_fifo_cmd |= GQSPI_GFIFO_RX |
			GQSPI_GFIFO_DATA_XFR_MASK;

	if (last_cmd == QUAD_OUT_READ_CMD)
		gen_fifo_cmd |= GQSPI_SPI_MODE_QSPI;
	else if (last_cmd == DUAL_OUTPUT_FASTRD_CMD)
		gen_fifo_cmd |= GQSPI_SPI_MODE_DUAL_SPI;
	else
		gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;

	if (priv->stripe)
		gen_fifo_cmd |= GQSPI_GFIFO_STRIPE_MASK;

	/*
	 * Check if receive buffer is aligned to 4 byte and length
	 * is multiples of four byte as we are using dma to receive.
	 */
	if ((!((unsigned long)priv->rx_buf & (GQSPI_DMA_ALIGN - 1)) &&
	     !(actuallen % GQSPI_DMA_ALIGN)) || priv->io_mode) {
		buf = (u32 *)priv->rx_buf;
		if (priv->io_mode)
			return zynqmp_qspi_start_io(priv, gen_fifo_cmd, buf);
		else
			return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
	}

	ALLOC_CACHE_ALIGN_BUFFER(u8, tmp, roundup(priv->len,
						  GQSPI_DMA_ALIGN));
	buf = (u32 *)tmp;
	return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
}
예제 #4
0
static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
{
	u32 gqspi_fifo_reg = 0;

	if (is_on) {
		gqspi_fifo_reg = zynqmp_qspi_bus_select(priv);
		gqspi_fifo_reg |= GQSPI_SPI_MODE_SPI |
				  GQSPI_IMD_DATA_CS_ASSERT;
	} else {
		if (priv->is_dual == SF_DUAL_PARALLEL_FLASH)
			gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS |
					 GQSPI_GFIFO_LOW_BUS;
		else if (priv->u_page)
			gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS;
		else
			gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS;
		gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT;
	}

	debug("GFIFO_CMD_CS: 0x%x\n", gqspi_fifo_reg);

	zynqmp_qspi_fill_gen_fifo(priv, gqspi_fifo_reg);
}
예제 #5
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, &regs->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;
}
예제 #6
0
static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on)
{
	u32 gqspi_fifo_reg = 0;
	struct zynqmp_qspi_regs *regs = priv->regs;

	if (is_on) {
		gqspi_fifo_reg = zynqmp_qspi_bus_select(priv);
		gqspi_fifo_reg |= ZYNQMP_QSPI_SPI_MODE_SPI |
				  ZYNQMP_QSPI_IMD_DATA_CS_ASSERT;
	} else {
		if (priv->is_dual == SF_DUAL_PARALLEL_FLASH)
			gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_UP_BUS |
					 ZYNQMP_QSPI_GFIFO_LOW_BUS;
		else if (priv->u_page)
			gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_UP_BUS;
		else
			gqspi_fifo_reg = ZYNQMP_QSPI_GFIFO_LOW_BUS;
		gqspi_fifo_reg |= ZYNQMP_QSPI_IMD_DATA_CS_DEASSERT;
	}

	debug("GFIFO_CMD_CS: 0x%x\n", gqspi_fifo_reg);

	writel(gqspi_fifo_reg, &regs->genfifo);
}
예제 #7
0
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, &regs->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;
}